summaryrefslogtreecommitdiff
path: root/skins/larry
diff options
context:
space:
mode:
authorThomas Bruederli <thomas@roundcube.net>2014-04-30 16:21:29 +0200
committerThomas Bruederli <thomas@roundcube.net>2014-04-30 16:21:29 +0200
commite8bcf08c72a18b3bf396e6448d6658227ecb46f2 (patch)
treedd4dc60d87f2340114eb9dcaaf7a567e09cdc995 /skins/larry
parent2d8f31da736550a0df3ccde31bf85a146aea45c0 (diff)
1. Prepare core and Larry skin for improved accessibility
2. Implement full keyboard navigation in main mail view
Diffstat (limited to 'skins/larry')
-rw-r--r--skins/larry/includes/header.html4
-rw-r--r--skins/larry/includes/mailtoolbar.html46
-rw-r--r--skins/larry/mail.css22
-rw-r--r--skins/larry/styles.css58
-rw-r--r--skins/larry/templates/login.html6
-rw-r--r--skins/larry/templates/mail.html20
-rw-r--r--skins/larry/ui.js98
7 files changed, 199 insertions, 55 deletions
diff --git a/skins/larry/includes/header.html b/skins/larry/includes/header.html
index 69e8b8aa6..8ce784b02 100644
--- a/skins/larry/includes/header.html
+++ b/skins/larry/includes/header.html
@@ -1,4 +1,4 @@
-<div id="header">
+<div id="header" role="banner">
<div id="topline">
<div class="topleft">
<roundcube:container name="topline-left" id="topline-left" />
@@ -21,7 +21,7 @@
<roundcube:if condition="!env:extwin &amp;&amp; !env:framed" />
<div id="topnav">
- <div id="taskbar" class="topright">
+ <div id="taskbar" class="topright" role="navigation" aria-label="Application Tasks">
<roundcube:button command="mail" label="mail" class="button-mail" classSel="button-mail button-selected" innerClass="button-inner" />
<roundcube:button command="addressbook" label="addressbook" class="button-addressbook" classSel="button-addressbook button-selected" innerClass="button-inner" />
<roundcube:container name="taskbar" id="taskbar" />
diff --git a/skins/larry/includes/mailtoolbar.html b/skins/larry/includes/mailtoolbar.html
index ac08a3200..5efea7cf7 100644
--- a/skins/larry/includes/mailtoolbar.html
+++ b/skins/larry/includes/mailtoolbar.html
@@ -3,11 +3,11 @@
<roundcube:button command="reply" type="link" class="button reply disabled" classAct="button reply" classSel="button reply pressed" label="reply" title="replytomessage" />
<span class="dropbutton">
<roundcube:button command="reply-all" type="link" class="button reply-all disabled" classAct="button reply-all" classSel="button reply-all pressed" label="replyall" title="replytoallmessage" />
- <span class="dropbuttontip" id="replyallmenulink" onclick="UI.show_popup('replyallmenu');return false"></span>
+ <span class="dropbuttontip" id="replyallmenulink" onclick="UI.toggle_popup('replyallmenu',event);return false"></span>
</span>
<span class="dropbutton">
<roundcube:button command="forward" type="link" class="button forward disabled" classAct="button forward" classSel="button forward pressed" label="forward" title="forwardmessage" />
- <span class="dropbuttontip" id="forwardmenulink" onclick="UI.show_popup('forwardmenu');return false"></span>
+ <span class="dropbuttontip" id="forwardmenulink" onclick="UI.toggle_popup('forwardmenu',event);return false"></span>
</span>
<roundcube:button command="delete" type="link" class="button delete disabled" classAct="button delete" classSel="button delete pressed" label="delete" title="deletemessage" />
<roundcube:if condition="template:name == 'message'" />
@@ -15,44 +15,44 @@
<roundcube:button command="print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="print" title="printmessage" />
<roundcube:endif />
<roundcube:container name="toolbar" id="mailtoolbar" />
-<roundcube:button name="markmenulink" id="markmessagemenulink" type="link" class="button markmessage" label="mark" title="markmessages" onclick="UI.show_popup('markmessagemenu');return false" />
-<roundcube:button name="messagemenulink" id="messagemenulink" type="link" class="button more" label="more" title="moreactions" onclick="UI.show_popup('messagemenu');return false" />
+<roundcube:button name="markmenulink" id="markmessagemenulink" type="link" class="button markmessage" label="mark" title="markmessages" onclick="UI.toggle_popup('markmessagemenu',event);return false" aria-haspopup="true" aria-owns="markmessagemenu" />
+<roundcube:button name="messagemenulink" id="messagemenulink" type="link" class="button more" label="more" title="moreactions" onclick="UI.toggle_popup('messagemenu',event);return false" aria-haspopup="true" aria-owns="messagemenu" />
<div id="forwardmenu" class="popupmenu">
- <ul class="toolbarmenu">
- <li><roundcube:button command="forward-inline" label="forwardinline" prop="sub" classAct="forwardlink active" class="forwardlink" /></li>
- <li><roundcube:button command="forward-attachment" label="forwardattachment" prop="sub" classAct="forwardattachmentlink active" class="forwardattachmentlink" /></li>
+ <ul class="toolbarmenu" role="menu">
+ <li role="menuitem"><roundcube:button command="forward-inline" label="forwardinline" prop="sub" classAct="forwardlink active" class="forwardlink" /></li>
+ <li role="menuitem"><roundcube:button command="forward-attachment" label="forwardattachment" prop="sub" classAct="forwardattachmentlink active" class="forwardattachmentlink" /></li>
<roundcube:container name="forwardmenu" id="forwardmenu" />
</ul>
</div>
<div id="replyallmenu" class="popupmenu">
- <ul class="toolbarmenu">
- <li><roundcube:button command="reply-all" label="replyall" prop="sub" class="replyalllink" classAct="replyalllink active" /></li>
- <li><roundcube:button command="reply-list" label="replylist" prop="sub" class="replylistlink" classAct="replylistlink active" /></li>
+ <ul class="toolbarmenu" role="menu">
+ <li role="menuitem"><roundcube:button command="reply-all" label="replyall" prop="sub" class="replyalllink" classAct="replyalllink active" /></li>
+ <li role="menuitem"><roundcube:button command="reply-list" label="replylist" prop="sub" class="replylistlink" classAct="replylistlink active" /></li>
<roundcube:container name="replyallmenu" id="replyallmenu" />
</ul>
</div>
<div id="messagemenu" class="popupmenu">
- <ul class="toolbarmenu iconized">
- <li><roundcube:button command="print" label="printmessage" class="icon" classAct="icon active" innerclass="icon print" /></li>
- <li><roundcube:button command="download" label="emlsave" class="icon" classAct="icon active" innerclass="icon download" /></li>
- <li><roundcube:button command="edit" prop="new" label="editasnew" class="icon" classAct="icon active" innerclass="icon edit" /></li>
- <li><roundcube:button command="viewsource" label="viewsource" class="icon" classAct="icon active" innerclass="icon viewsource" /></li>
- <li><roundcube:button command="move" label="moveto" class="icon" classAct="icon active" innerclass="icon move folder-selector-link" /></li>
- <li><roundcube:button command="copy" label="copyto" class="icon" classAct="icon active" innerclass="icon copy folder-selector-link" /></li>
- <li><roundcube:button command="open" label="openinextwin" target="_blank" class="icon" classAct="icon active" innerclass="icon extwin" /></li>
+ <ul class="toolbarmenu iconized" role="menu">
+ <li role="menuitem"><roundcube:button command="print" label="printmessage" class="icon" classAct="icon active" innerclass="icon print" /></li>
+ <li role="menuitem"><roundcube:button command="download" label="emlsave" class="icon" classAct="icon active" innerclass="icon download" /></li>
+ <li role="menuitem"><roundcube:button command="edit" prop="new" label="editasnew" class="icon" classAct="icon active" innerclass="icon edit" /></li>
+ <li role="menuitem"><roundcube:button command="viewsource" label="viewsource" class="icon" classAct="icon active" innerclass="icon viewsource" /></li>
+ <li role="menuitem"><roundcube:button command="move" label="moveto" class="icon" classAct="icon active" innerclass="icon move folder-selector-link" /></li>
+ <li role="menuitem"><roundcube:button command="copy" label="copyto" class="icon" classAct="icon active" innerclass="icon copy folder-selector-link" /></li>
+ <li role="menuitem"><roundcube:button command="open" label="openinextwin" target="_blank" class="icon" classAct="icon active" innerclass="icon extwin" /></li>
<roundcube:container name="messagemenu" id="messagemenu" />
</ul>
</div>
<div id="markmessagemenu" class="popupmenu">
- <ul class="toolbarmenu iconized">
- <li><roundcube:button command="mark" prop="read" label="markread" classAct="icon active" class="icon" innerclass="icon read" /></li>
- <li><roundcube:button command="mark" prop="unread" label="markunread" classAct="icon active" class="icon" innerclass="icon unread" /></li>
- <li><roundcube:button command="mark" prop="flagged" label="markflagged" classAct="icon active" class="icon" innerclass="icon flagged" /></li>
- <li><roundcube:button command="mark" prop="unflagged" label="markunflagged" classAct="icon active" class="icon" innerclass="icon unflagged" /></li>
+ <ul class="toolbarmenu iconized" role="menu">
+ <li role="menuitem"><roundcube:button command="mark" prop="read" label="markread" classAct="icon active" class="icon" innerclass="icon read" /></li>
+ <li role="menuitem"><roundcube:button command="mark" prop="unread" label="markunread" classAct="icon active" class="icon" innerclass="icon unread" /></li>
+ <li role="menuitem"><roundcube:button command="mark" prop="flagged" label="markflagged" classAct="icon active" class="icon" innerclass="icon flagged" /></li>
+ <li role="menuitem"><roundcube:button command="mark" prop="unflagged" label="markunflagged" classAct="icon active" class="icon" innerclass="icon unflagged" /></li>
<roundcube:container name="markmenu" id="markmessagemenu" />
</ul>
</div>
diff --git a/skins/larry/mail.css b/skins/larry/mail.css
index b9f24b8d0..a3f7e7ba8 100644
--- a/skins/larry/mail.css
+++ b/skins/larry/mail.css
@@ -158,6 +158,7 @@ a.iconbutton.threadmode.selected {
padding-right: 36px;
}
+#mailboxlist li.mailbox > a:focus,
#mailboxlist li.mailbox.selected > a {
background-position: 6px -21px;
}
@@ -166,6 +167,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -189px;
}
+#mailboxlist li.mailbox.inbox > a:focus,
#mailboxlist li.mailbox.inbox.selected > a {
background-position: 6px -213px;
}
@@ -174,6 +176,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -238px;
}
+#mailboxlist li.mailbox.drafts > a:focus,
#mailboxlist li.mailbox.drafts.selected > a {
background-position: 6px -262px;
}
@@ -182,6 +185,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -286px;
}
+#mailboxlist li.mailbox.sent > a:focus,
#mailboxlist li.mailbox.sent.selected > a {
background-position: 6px -310px;
}
@@ -190,6 +194,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -334px;
}
+#mailboxlist li.mailbox.junk > a:focus,
#mailboxlist li.mailbox.junk.selected > a {
background-position: 6px -358px;
}
@@ -198,6 +203,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -382px;
}
+#mailboxlist li.mailbox.trash > a:focus,
#mailboxlist li.mailbox.trash.selected > a {
background-position: 6px -406px;
}
@@ -206,6 +212,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -1924px;
}
+#mailboxlist li.mailbox.trash.empty > a:focus,
#mailboxlist li.mailbox.trash.empty.selected > a {
background-position: 6px -1948px;
}
@@ -214,6 +221,7 @@ a.iconbutton.threadmode.selected {
background-position: 6px -1699px;
}
+#mailboxlist li.mailbox.archive > a:focus,
#mailboxlist li.mailbox.archive.selected > a {
background-position: 6px -1723px;
}
@@ -222,6 +230,7 @@ a.iconbutton.threadmode.selected {
background-position: 23px -238px;
}
+#mailboxlist li.mailbox ul li.drafts > a:focus,
#mailboxlist li.mailbox ul li.drafts.selected > a {
background-position: 23px -262px;
}
@@ -230,6 +239,7 @@ a.iconbutton.threadmode.selected {
background-position: 23px -286px;
}
+#mailboxlist li.mailbox ul li.sent > a:focus,
#mailboxlist li.mailbox ul li.sent.selected > a {
background-position: 23px -310px;
}
@@ -238,6 +248,7 @@ a.iconbutton.threadmode.selected {
background-position: 23px -334px;
}
+#mailboxlist li.mailbox ul li.junk > a:focus,
#mailboxlist li.mailbox ul li.junk.selected > a {
background-position: 23px -358px;
}
@@ -246,6 +257,7 @@ a.iconbutton.threadmode.selected {
background-position: 23px -382px;
}
+#mailboxlist li.mailbox ul li.trash > a:focus,
#mailboxlist li.mailbox ul li.trash.selected > a {
background-position: 23px -406px;
}
@@ -254,6 +266,7 @@ a.iconbutton.threadmode.selected {
background-position: 23px -1924px;
}
+#mailboxlist li.mailbox ul li.trash.empty > a:focus,
#mailboxlist li.mailbox ul li.trash.empty.selected > a {
background-position: 23px -1948px;
}
@@ -262,6 +275,7 @@ a.iconbutton.threadmode.selected {
background-position: 23px -1699px;
}
+#mailboxlist li.mailbox ul li.archive > a:focus,
#mailboxlist li.mailbox ul li.archive.selected > a {
background-position: 23px -1723px;
}
@@ -300,6 +314,7 @@ a.iconbutton.threadmode.selected {
padding-left: 52px; /* 36 + 1 x 16 */
background-position: 22px -93px; /* 6 + 1 x 16 */
}
+#mailboxlist li.mailbox ul li > a:focus,
#mailboxlist li.mailbox ul li.selected > a {
background-position: 22px -117px;
}
@@ -312,6 +327,7 @@ a.iconbutton.threadmode.selected {
padding-left: 68px; /* 2x */
background-position: 38px -93px;
}
+#mailboxlist li.mailbox ul ul li > a:focus,
#mailboxlist li.mailbox ul ul li.selected > a {
background-position: 38px -117px;
}
@@ -323,6 +339,7 @@ a.iconbutton.threadmode.selected {
padding-left: 84px; /* 3x */
background-position: 54px -93px;
}
+#mailboxlist li.mailbox ul ul ul li > a:focus,
#mailboxlist li.mailbox ul ul ul li.selected > a {
background-position: 54px -117px;
}
@@ -334,6 +351,7 @@ a.iconbutton.threadmode.selected {
padding-left: 100px; /* 4x */
background-position: 70px -93px;
}
+#mailboxlist li.mailbox ul ul ul ul li > a:focus,
#mailboxlist li.mailbox ul ul ul ul li.selected > a {
background-position: 70px -117px;
}
@@ -544,7 +562,9 @@ table.messagelist.fixedcopy {
.messagelist thead tr td.sortedDESC a {
color: #004458;
text-decoration: underline;
- background: url(images/listicons.png) right -912px no-repeat;
+ background-image: url(images/listicons.png);
+ background-repeat: no-repeat;
+ background-position: right -912px;
}
.messagelist thead tr td.sortedASC a {
diff --git a/skins/larry/styles.css b/skins/larry/styles.css
index 660daa943..4ef57e722 100644
--- a/skins/larry/styles.css
+++ b/skins/larry/styles.css
@@ -945,6 +945,13 @@ a.iconlink.upload {
background: url(images/buttons.png) -1000px 0 no-repeat;
}
+#taskbar a:focus {
+ color: #fff;
+ text-shadow: 0px 1px 1px #666;
+ background-color: #3da0c2;
+ outline: none;
+}
+
#taskbar a.button-selected {
color: #3cf;
background-color: #2c2c2c;
@@ -1240,6 +1247,13 @@ ul.treelist li a {
text-overflow: ellipsis;
}
+ul.treelist li a:focus {
+ color: #fff;
+ background: #4db0d2;
+ text-shadow: 0px 1px 1px #666;
+ outline: none;
+}
+
ul.treelist ul li a {
padding-left: 38px;
}
@@ -1320,6 +1334,13 @@ ul.treelist li.selected > div.expanded {
margin-top: 1px;
}
+.boxfooter a.listbutton:focus {
+ color: #fff;
+ background: #4db0d2;
+ text-shadow: 0px 1px 1px #666;
+ outline: none;
+}
+
.uibox .boxfooter .listbutton:first-child {
border-radius: 0 0 0 4px;
}
@@ -1329,7 +1350,9 @@ ul.treelist li.selected > div.expanded {
width: 48px;
height: 35px;
text-indent: -5000px;
- background: url(images/buttons.png) -1000px 0 no-repeat;
+ background-image: url(images/buttons.png);
+ background-position: -1000px 0;
+ background-repeat: no-repeat;
}
.boxfooter .listbutton.add .inner {
@@ -1473,6 +1496,13 @@ table.records-table {
text-overflow: ellipsis;
}
+.records-table thead td a:focus {
+ color: #fff;
+ background: #4db0d2;
+ text-shadow: 0px 1px 1px #666;
+ outline: none;
+}
+
.records-table tbody td {
padding: 2px 7px;
border-bottom: 1px solid #ddd;
@@ -1492,12 +1522,12 @@ table.records-table {
}
/* because of border-collapse, we make the left border twice what we want it to be - half will be hidden to the left */
-.records-table tbody tr.focused > td:first-child {
+.records-table.focus tbody tr.focused > td:first-child {
border-left: 2px solid #b0ccd7;
padding-left: 4px;
}
-.records-table tbody tr.selected.focused > td:first-child {
+.records-table.focus tbody tr.selected.focused > td:first-child {
border-left-color: #49b3d2;
}
@@ -1908,6 +1938,13 @@ ul.proplist li {
border-radius: 0;
}
+.toolbar a.button:focus {
+ color: #fff;
+ text-shadow: 0px 1px 1px #666;
+ background-color: #4db0d2;
+ border-radius: 4px;
+}
+
.toolbar a.button.disabled {
opacity: 0.4;
filter: alpha(opacity=40);
@@ -2119,6 +2156,19 @@ select.decorated option {
}
+a.menuselector:focus,
+a.menuselector.focus,
+a.iconbutton:focus,
+.pagenav a.button:focus {
+ border-color: #4fadd5;
+ -webkit-box-shadow: 0 0 4px 2px rgba(71,135,177, 0.8);
+ -moz-box-shadow: 0 0 4px 2px rgba(71,135,177, 0.8);
+ -o-box-shadow: 0 0 4px 2px rgba(71,135,177, 0.8);
+ box-shadow: 0 0 4px 2px rgba(71,135,177, 0.8);
+ outline: none;
+}
+
+
/*** quota indicator ***/
#quotadisplay {
@@ -2211,6 +2261,7 @@ ul.toolbarmenu li a.active {
.googie_list td.googie_list_onhover,
ul.toolbarmenu li a.active:hover,
+ul.toolbarmenu li a.active:focus,
#rcmKSearchpane ul li.selected,
select.decorated option:hover,
select.decorated option[selected='selected'] {
@@ -2220,6 +2271,7 @@ select.decorated option[selected='selected'] {
background: -o-linear-gradient(top, #00aad6 0%, #008fc9 100%);
background: -ms-linear-gradient(top, #00aad6 0%, #008fc9 100%);
background: linear-gradient(top, #00aad6 0%, #008fc9 100%);
+ outline: none;
}
ul.toolbarmenu.iconized li a,
diff --git a/skins/larry/templates/login.html b/skins/larry/templates/login.html
index 64ff6be92..b14d1965e 100644
--- a/skins/larry/templates/login.html
+++ b/skins/larry/templates/login.html
@@ -8,7 +8,7 @@
<body>
<div id="login-form">
-<div class="box-inner">
+<div class="box-inner" role="main">
<roundcube:object name="logo" src="/images/roundcube_logo.png" id="logo" />
<roundcube:form name="form" method="post">
@@ -17,14 +17,14 @@
</div>
-<div class="box-bottom">
+<div class="box-bottom" role="complementary">
<roundcube:object name="message" id="message" />
<noscript>
<p class="noscriptwarning"><roundcube:label name="noscriptwarning" /></p>
</noscript>
</div>
-<div id="bottomline">
+<div id="bottomline" role="contentinfo">
<roundcube:var name="config:product_name"> <roundcube:object name="version" condition="config:display_version" />
<roundcube:if condition="config:support_url" />
&nbsp;&#9679;&nbsp; <a href="<roundcube:var name='config:support_url' />" target="_blank" class="support-link"><roundcube:label name="support" /></a>
diff --git a/skins/larry/templates/mail.html b/skins/larry/templates/mail.html
index 1e4a3ce8c..d92324fe8 100644
--- a/skins/larry/templates/mail.html
+++ b/skins/larry/templates/mail.html
@@ -18,7 +18,7 @@
<div id="mainscreen">
<!-- toolbar -->
-<div id="messagetoolbar" class="toolbar">
+<div id="messagetoolbar" class="toolbar" role="toolbar">
<roundcube:button command="checkmail" type="link" class="button checkmail disabled" classAct="button checkmail" classSel="button checkmail pressed" label="refresh" title="checkmail" />
<roundcube:include file="/includes/mailtoolbar.html" />
</div>
@@ -27,13 +27,13 @@
<!-- search filter -->
<div id="searchfilter">
- <roundcube:object name="searchfilter" class="searchfilter decorated" />
+ <roundcube:object name="searchfilter" class="searchfilter decorated" aria-controls="messagelist" />
</div>
<!-- search box -->
-<div id="quicksearchbar" class="searchbox">
+<div id="quicksearchbar" class="searchbox" role="search" aria-label="Email message search form">
<roundcube:object name="searchform" id="quicksearchbox" />
-<roundcube:button name="searchmenulink" id="searchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('searchmenu');return false" title="searchmod" content=" " />
+<roundcube:button name="searchmenulink" id="searchmenulink" class="iconbutton searchoptions" onclick="UI.toggle_popup('searchmenu',event);return false" title="searchmod" content=" " />
<roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
</div>
@@ -43,12 +43,12 @@
<div id="mailview-left">
<!-- folders list -->
-<div id="mailboxcontainer" class="uibox listbox">
+<div id="mailboxcontainer" class="uibox listbox" role="navigation" aria-label="Email folder selection">
<div id="folderlist-content" class="scroller withfooter">
<roundcube:object name="mailboxlist" id="mailboxlist" class="treelist listing" folder_filter="mail" unreadwrap="%s" />
</div>
<div id="folderlist-footer" class="boxfooter">
- <roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="listbutton groupactions" onclick="UI.show_popup('mailboxmenu');return false" innerClass="inner" content="&#9881;" />
+ <roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="listbutton groupactions" onclick="UI.toggle_popup('mailboxmenu',event);return false" innerClass="inner" content="&#9881;" />
<roundcube:if condition="env:quota" />
<roundcube:object name="quotaDisplay" id="quotadisplay" class="countdisplay" display="text" />
<roundcube:endif />
@@ -57,7 +57,7 @@
</div>
-<div id="mailview-right">
+<div id="mailview-right" role="main">
<roundcube:if condition="config:preview_pane == true" />
<div id="mailview-top" class="uibox">
@@ -81,9 +81,9 @@
</div>
<div id="listselectors">
- <a href="#select" id="listselectmenulink" class="menuselector" onclick="UI.show_popup('listselectmenu');return false"><span class="handle"><roundcube:label name="select" /></span></a>
+ <a href="#select" id="listselectmenulink" class="menuselector" onclick="UI.toggle_popup('listselectmenu', event);return false" aria-haspopup="true" aria-owns="listselectmenu"><span class="handle"><roundcube:label name="select" /></span></a>
<roundcube:if condition="env:threads" />
- &nbsp; <a href="#threads" id="threadselectmenulink" class="menuselector" onclick="UI.show_popup('threadselectmenu');return false"><span class="handle"><roundcube:label name="threads" /></span></a>
+ &nbsp; <a href="#threads" id="threadselectmenulink" class="menuselector" onclick="UI.toggle_popup('threadselectmenu', event);return false" aria-haspopup="true" aria-owns="threadselectmenu"><span class="handle"><roundcube:label name="threads" /></span></a>
<roundcube:endif />
</div>
@@ -99,7 +99,7 @@
<roundcube:container name="listcontrols" id="listcontrols" />
- <a href="#preview" id="mailpreviewtoggle" title="<roundcube:label name='previewpane' />"></a>
+ <a href="#preview" id="mailpreviewtoggle" class="iconbutton" title="<roundcube:label name='previewpane' />" role="button" tabindex="0"></a>
</div>
</div><!-- end mailview-top -->
diff --git a/skins/larry/ui.js b/skins/larry/ui.js
index 0e8afc652..add02b85e 100644
--- a/skins/larry/ui.js
+++ b/skins/larry/ui.js
@@ -33,6 +33,8 @@ function rcube_mail_ui()
var mailviewsplit;
var compose_headers = {};
var prefs;
+ var focused_popup;
+ var popup_keyboard_active = false;
// export public methods
this.set = setenv;
@@ -40,6 +42,7 @@ function rcube_mail_ui()
this.init_tabs = init_tabs;
this.show_about = show_about;
this.show_popup = show_popup;
+ this.toggle_popup = toggle_popup;
this.add_popup = add_popup;
this.set_searchmod = set_searchmod;
this.set_searchscope = set_searchscope;
@@ -333,6 +336,10 @@ function rcube_mail_ui()
var val = $('option:selected', this).text();
$(this).next().children().text(val);
});
+
+ select
+ .on('focus', function(e){ overlay.addClass('focus'); })
+ .on('blur', function(e){ overlay.removeClass('focus'); });
});
// set min-width to show all toolbar buttons
@@ -343,14 +350,7 @@ function rcube_mail_ui()
$(document.body)
.bind('mouseup', body_mouseup)
- .bind('keyup', function(e){
- if (e.keyCode == 27) {
- for (var id in popups) {
- if (popups[id].is(':visible'))
- show_popup(id, false);
- }
- }
- });
+ .bind('keydown', popup_keypress);
$('iframe').load(function(e){
// this = iframe
@@ -586,13 +586,21 @@ function rcube_mail_ui()
/**
* Trigger for popup menus
*/
- function show_popup(popup, show, config)
+ function toggle_popup(popup, e, config)
+ {
+ show_popup(popup, undefined, config, rcube_event.is_keyboard(e));
+ }
+
+ /**
+ * (Deprecated) trigger for popup menus
+ */
+ function show_popup(popup, show, config, keyboard)
{
// auto-register menu object
if (config || !popupconfig[popup])
add_popup(popup, config);
- var visible = show_popupmenu(popup, show),
+ var visible = show_popupmenu(popup, show, keyboard),
config = popupconfig[popup];
if (typeof config.callback == 'function')
config.callback(visible);
@@ -601,7 +609,7 @@ function rcube_mail_ui()
/**
* Show/hide a specific popup menu
*/
- function show_popupmenu(popup, show)
+ function show_popupmenu(popup, show, keyboard)
{
var obj = popups[popup],
config = popupconfig[popup],
@@ -638,12 +646,76 @@ function rcube_mail_ui()
obj.css({ left:pos.left, top:(pos.top + (above ? -obj.height() : ref.offsetHeight)) });
}
+ else if (!show && keyboard && ref.length) {
+ ref.focus();
+ }
obj[show?'show':'hide']();
+ popup_keyboard_active = show && keyboard;
+ if (popup_keyboard_active) {
+ focused_popup = popup;
+ obj.find('a,input').not('[aria-disabled=true]').first().focus();
+ }
+ else {
+ focused_popup = null;
+ }
+
return show;
}
+ /**
+ * Handler for keyboard events on active popups
+ */
+ function popup_keypress(e)
+ {
+ var target = e.target || {},
+ keyCode = rcube_event.get_keycode(e);
+
+ if (e.keyCode != 27 && (!popup_keyboard_active || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT'))
+ return true;
+
+ switch (keyCode) {
+ case 38:
+ case 40:
+ case 63232: // "up", in safari keypress
+ case 63233: // "down", in safari keypress
+ popup_focus_item(mod = keyCode == 38 || keyCode == 63232 ? -1 : 1);
+ break;
+
+ case 9: // tab
+ if (focused_popup) {
+ var mod = rcube_event.get_modifier(e);
+ if (!popup_focus_item(mod == SHIFT_KEY ? -1 : 1)) {
+ show_popup(focused_popup, false, undefined, true);
+ }
+ }
+ return rcube_event.cancel(e);
+
+ case 27: // esc
+ for (var id in popups) {
+ if (popups[id].is(':visible'))
+ show_popup(id, false, undefined, true);
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Helper method to move focus to the next/prev popup menu item
+ */
+ function popup_focus_item(dir)
+ {
+ var obj, mod = dir < 0 ? 'prevAll' : 'nextAll', limit = dir < 0 ? 'last' : 'first';
+ if (focused_popup && (obj = popups[focused_popup])) {
+ return obj.find(':focus').closest('li')[mod](':has(:not([aria-disabled=true]))').find('a,input')[limit]().focus().length;
+ }
+
+ return 0;
+ }
+
/**
*
*/
@@ -734,8 +806,8 @@ function rcube_mail_ui()
function switch_view_mode(mode, force)
{
if (force || !$('#mail'+mode+'mode').hasClass('disabled')) {
- $('#maillistmode, #mailthreadmode').removeClass('selected');
- $('#mail'+mode+'mode').addClass('selected');
+ $('#maillistmode, #mailthreadmode').removeClass('selected').attr('tabindex', '0').attr('aria-disabled', 'false');
+ $('#mail'+mode+'mode').addClass('selected').attr('tabindex', '-1').attr('aria-disabled', 'true');
}
}