diff options
| -rw-r--r-- | program/js/app.js | 104 | ||||
| -rw-r--r-- | program/js/list.js | 58 | ||||
| -rw-r--r-- | skins/classic/common.css | 3 | ||||
| -rw-r--r-- | skins/larry/styles.css | 2 | 
4 files changed, 115 insertions, 52 deletions
| diff --git a/program/js/app.js b/program/js/app.js index 41f9a3859..bf163c614 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -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+'"> </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+'"> </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+'"> </span>'; +          html = '<span class="'+flags.attachmentClass+'" title="'+label+'"></span>';          else if (/application\/|multipart\/(m|signed)/.test(flags.ctype)) -          html = '<span class="attachment"> </span>'; +          html = '<span class="attachment" title="'+label+'"></span>';          else if (/multipart\/report/.test(flags.ctype)) -          html = '<span class="report"> </span>'; -        else +          html = '<span class="report"></span>'; +          else            html = ' ';        }        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+'"> </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+'"> </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 = ' ';        } @@ -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);      }    }; diff --git a/program/js/list.js b/program/js/list.js index 62f1b1c9d..0bf5d568b 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -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; diff --git a/skins/classic/common.css b/skins/classic/common.css index 4367d26cb..126408444 100644 --- a/skins/classic/common.css +++ b/skins/classic/common.css @@ -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 diff --git a/skins/larry/styles.css b/skins/larry/styles.css index a84202800..d7ad74c01 100644 --- a/skins/larry/styles.css +++ b/skins/larry/styles.css @@ -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 */ | 
