From a2f8fa236143b44f90e53c19806cfd0efa014857 Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Mon, 12 May 2014 04:32:45 -0400
Subject: [PATCH] Set aria-selected and aria-expanded state attributes

---
 program/js/list.js                    |   12 ++++++------
 skins/larry/templates/mail.html       |    9 ++++-----
 program/js/treelist.js                |   13 ++++++++-----
 skins/larry/includes/mailtoolbar.html |    8 ++++----
 program/js/app.js                     |    8 +++++---
 skins/larry/templates/compose.html    |    6 +++---
 6 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index dd172cd..06008b2 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -6967,7 +6967,7 @@
         this.hide_menu(this.menu_stack[0], event);
       }
 
-      obj.show().attr('aria-hidden', 'false').data('opener', ref.get(0));
+      obj.show().attr('aria-hidden', 'false').data('opener', ref.attr('aria-expanded', 'true').get(0));
       this.triggerEvent('menu-open', { name:name, obj:obj, props:prop, originalEvent:event });
       this.menu_stack.push(name);
 
@@ -6999,8 +6999,10 @@
       this.triggerEvent('menu-close', { name:this.menu_stack[j], obj:obj, props:{ menu:this.menu_stack[j] }, originalEvent:event });
       if (this.menu_stack[j] == name) {
         j = -1;  // stop loop
-        if (keyboard && obj.data('opener')) {
-          obj.data('opener').focus();
+        if (obj.data('opener')) {
+          $(obj.data('opener')).attr('aria-expanded', 'false');
+          if (keyboard)
+            obj.data('opener').focus();
         }
       }
       this.menu_stack.pop();
diff --git a/program/js/list.js b/program/js/list.js
index fa37353..f64d38b 100644
--- a/program/js/list.js
+++ b/program/js/list.js
@@ -116,7 +116,7 @@
       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('Select List')
+        .html($(this.list).attr('summary') || 'Select List')
         .insertAfter(this.list)
         .on('focus', function(e){ me.focus(e); })
         .on('blur', function(e){ me.blur(e); });
@@ -1086,7 +1086,7 @@
       this.highlight_row(n, true, true);
     }
     else {
-      $(this.rows[n].obj).removeClass('selected').removeClass('unfocused');
+      $(this.rows[n].obj).removeClass('selected').removeClass('unfocused').removeAttr('aria-selected');
     }
   }
 
@@ -1143,7 +1143,7 @@
   else {
     for (n in this.selection)
       if (this.rows[this.selection[n]]) {
-        $(this.rows[this.selection[n]].obj).removeClass('selected').removeClass('unfocused');
+        $(this.rows[this.selection[n]].obj).removeClass('selected').removeClass('unfocused').removeAttr('aria-selected');
       }
 
     this.selection = [];
@@ -1206,13 +1206,13 @@
     if (this.selection.length > 1 || !this.in_selection(id)) {
       this.clear_selection(null, true);
       this.selection[0] = id;
-      $(this.rows[id].obj).addClass('selected');
+      $(this.rows[id].obj).addClass('selected').attr('aria-selected', 'true');
     }
   }
   else {
     if (!this.in_selection(id)) { // select row
       this.selection.push(id);
-      $(this.rows[id].obj).addClass('selected');
+      $(this.rows[id].obj).addClass('selected').attr('aria-selected', 'true');
       if (!norecur && !this.rows[id].expanded)
         this.highlight_children(id, true);
     }
@@ -1222,7 +1222,7 @@
         a_post = this.selection.slice(p+1, this.selection.length);
 
       this.selection = a_pre.concat(a_post);
-      $(this.rows[id].obj).removeClass('selected').removeClass('unfocused');
+      $(this.rows[id].obj).removeClass('selected').removeClass('unfocused').removeAttr('aria-selected');
       if (!norecur && !this.rows[id].expanded)
         this.highlight_children(id, false);
     }
diff --git a/program/js/treelist.js b/program/js/treelist.js
index fa39078..8b55b32 100644
--- a/program/js/treelist.js
+++ b/program/js/treelist.js
@@ -323,7 +323,7 @@
    */
   function update_data()
   {
-    data = walk_list(container);
+    data = walk_list(container, 0);
   }
 
   /**
@@ -332,6 +332,7 @@
   function update_dom(node)
   {
     var li = id2dom(node.id);
+    li.attr('aria-expanded', node.collapsed ? 'false' : 'true');
     li.children('ul').first()[(node.collapsed ? 'hide' : 'show')]();
     li.children('div.treetoggle').removeClass('collapsed expanded').addClass(node.collapsed ? 'collapsed' : 'expanded');
     me.triggerEvent('toggle', node);
@@ -400,8 +401,9 @@
 
     // add child list and toggle icon
     if (node.children && node.children.length) {
+      li.attr('aria-expanded', node.collapsed ? 'false' : 'true');
       $('<div class="treetoggle '+(node.collapsed ? 'collapsed' : 'expanded') + '">&nbsp;</div>').appendTo(li);
-      var ul = $('<ul>').appendTo(li).attr('class', node.childlistclass).attr('role', 'tree');
+      var ul = $('<ul>').appendTo(li).attr('class', node.childlistclass).attr('role', 'group');
       if (node.collapsed)
         ul.hide();
 
@@ -417,7 +419,7 @@
    * Recursively walk the DOM tree and build an internal data structure
    * representing the skeleton of this tree list.
    */
-  function walk_list(ul)
+  function walk_list(ul, level)
   {
     var result = [];
     ul.children('li').each(function(i,e){
@@ -427,7 +429,7 @@
         classes: li.attr('class').split(' '),
         virtual: li.hasClass('virtual'),
         html: li.children().first().get(0).outerHTML,
-        children: walk_list(sublist)
+        children: walk_list(sublist, level+1)
       }
 
       if (sublist.length) {
@@ -435,6 +437,7 @@
       }
       if (node.children.length) {
         node.collapsed = sublist.css('display') == 'none';
+        li.attr('aria-expanded', node.collapsed ? 'false' : 'true');
       }
       if (li.hasClass('selected')) {
         li.attr('aria-selected', 'true');
@@ -453,7 +456,7 @@
       indexbyid[node.id] = node;
     });
 
-    ul.attr('role', 'tree');
+    ul.attr('role', level == 0 ? 'tree' : 'group');
 
     return result;
   }
diff --git a/skins/larry/includes/mailtoolbar.html b/skins/larry/includes/mailtoolbar.html
index 6af114a..a70cc02 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" />
-	<a href="#reply-all" class="dropbuttontip" id="replyallmenulink" onclick="UI.toggle_popup('replyallmenu',event);return false" aria-haspopup="true" aria-owns="replyallmenu-menu" tabindex="0">Reply-all options</a>
+	<a href="#reply-all" class="dropbuttontip" id="replyallmenulink" onclick="UI.toggle_popup('replyallmenu',event);return false" aria-haspopup="true" aria-expanded="false"aria-owns="replyallmenu-menu" tabindex="0">Reply-all options</a>
 </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" />
-	<a href="#reply-all" class="dropbuttontip" id="forwardmenulink" onclick="UI.toggle_popup('forwardmenu',event);return false" aria-haspopup="true" aria-owns="forwardmenu-menu" tabindex="0">Forwarding options</a>
+	<a href="#reply-all" class="dropbuttontip" id="forwardmenulink" onclick="UI.toggle_popup('forwardmenu',event);return false" aria-haspopup="true" aria-expanded="false"aria-owns="forwardmenu-menu" tabindex="0">Forwarding options</a>
 </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,8 +15,8 @@
 <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.toggle_popup('markmessagemenu',event);return false" aria-haspopup="true" aria-owns="markmessagemenu-menu" />
-<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-menu" />
+<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-expanded="false"aria-owns="markmessagemenu-menu" />
+<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-expanded="false"aria-owns="messagemenu-menu" />
 
 <div id="forwardmenu" class="popupmenu" aria-hidden="true">
 	<h3 id="aria-label-forwardmenu" class="voice">Forwarding options</h3>
diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html
index 14f5a6d..7b229f3 100644
--- a/skins/larry/templates/compose.html
+++ b/skins/larry/templates/compose.html
@@ -27,12 +27,12 @@
 	<roundcube:if condition="config:enable_spellcheck" />
 	<span class="dropbutton">
 		<roundcube:button command="spellcheck" type="link" class="button spellcheck disabled" classAct="button spellcheck" classSel="button spellcheck pressed" label="spellcheck" title="checkspelling" tabindex="2" />
-		<a href="#languages" class="dropbuttontip" id="spellmenulink" onclick="UI.toggle_popup('spellmenu',event);return false" aria-haspopup="true" tabindex="2">Select Spell Language</a>
+		<a href="#languages" class="dropbuttontip" id="spellmenulink" onclick="UI.toggle_popup('spellmenu',event);return false" aria-haspopup="true" aria-expanded="false"tabindex="2">Select Spell Language</a>
 	</span>
 	<roundcube:endif />
-	<roundcube:button name="addattachment" type="link" class="button attach" label="attach" title="addattachment" onclick="UI.show_uploadform(event);return false" aria-haspopup="true" tabindex="2" />
+	<roundcube:button name="addattachment" type="link" class="button attach" label="attach" title="addattachment" onclick="UI.show_uploadform(event);return false" aria-haspopup="true" aria-expanded="false"tabindex="2" />
 	<roundcube:button command="insert-sig" type="link" class="button insertsig disabled" classAct="button insertsig" label="signature" title="insertsignature" tabindex="2" />
-	<a href="#responses" class="button responses" label="responses" title="<roundcube:label name='insertresponse' />" id="responsesmenulink" unselectable="on" onmousedown="return false" onclick="UI.toggle_popup('responsesmenu',event);return false" tabindex="2" aria-haspopup="true" aria-owns="textresponsesmenu"><roundcube:label name="responses" /></a>
+	<a href="#responses" class="button responses" label="responses" title="<roundcube:label name='insertresponse' />" id="responsesmenulink" unselectable="on" onmousedown="return false" onclick="UI.toggle_popup('responsesmenu',event);return false" tabindex="2" aria-haspopup="true" aria-expanded="false"aria-owns="textresponsesmenu"><roundcube:label name="responses" /></a>
 	<roundcube:container name="toolbar" id="compose-toolbar" />
 </div>
 
diff --git a/skins/larry/templates/mail.html b/skins/larry/templates/mail.html
index 1e360b4..3d91629 100644
--- a/skins/larry/templates/mail.html
+++ b/skins/larry/templates/mail.html
@@ -39,7 +39,7 @@
 <h2 id="aria-label-searchform" class="voice">Email message search form</h2>
 <label for="quicksearchbox" class="voice">Email search input</label>
 <roundcube:object name="searchform" id="quicksearchbox" />
-<roundcube:button command="menu-open" prop="searchmenu" id="searchmenulink" class="iconbutton searchoptions" title="searchmod" label="options" aria-haspopup="true" aria-owns="searchmenu-menu" />
+<roundcube:button command="menu-open" prop="searchmenu" id="searchmenulink" class="iconbutton searchoptions" title="searchmod" label="options" aria-haspopup="true" aria-expanded="false"aria-owns="searchmenu-menu" />
 <roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" content="Reset" />
 
 <div id="searchmenu" class="popupmenu" data-editable="true">
@@ -73,7 +73,7 @@
 <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.toggle_popup('mailboxmenu',event);return false" innerClass="inner" content="&#9881;" aria-haspopup="true" aria-owns="mailboxmenu-menu" />
+	<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;" aria-haspopup="true" aria-expanded="false"aria-owns="mailboxmenu-menu" />
 	<roundcube:if condition="env:quota" />
 		<roundcube:object name="quotaDisplay" id="quotadisplay" class="countdisplay" display="text" />
 	<roundcube:endif />
@@ -98,7 +98,6 @@
 	class="records-table messagelist sortheader fixedheader"
 	optionsmenuIcon="true"
 	summary="Email Messages Listing"
-	role="grid"
 	aria-labelledby="aria-label-messagelist" />
 </div>
 
@@ -110,9 +109,9 @@
 	</div>
 	
 	<div id="listselectors">
-	<a href="#select" id="listselectmenulink" class="menuselector" onclick="UI.toggle_popup('listselectmenu', event);return false" aria-haspopup="true" aria-owns="listselectmenu-menu"><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-expanded="false"aria-owns="listselectmenu-menu"><span class="handle"><roundcube:label name="select" /></span></a>
 	<roundcube:if condition="env:threads" />
-		&nbsp; <a href="#threads" id="threadselectmenulink" class="menuselector" onclick="UI.toggle_popup('threadselectmenu', event);return false" aria-haspopup="true" aria-owns="threadselectmenu-menu"><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-expanded="false"aria-owns="threadselectmenu-menu"><span class="handle"><roundcube:label name="threads" /></span></a>
 	<roundcube:endif />
 	</div>
 

--
Gitblit v1.9.1