plugins/kolab_files

Aleksander Machniak machniak at kolabsys.com
Thu Jun 12 12:56:35 CEST 2014


 plugins/kolab_files/kolab_files.js                            |  169 +++++++---
 plugins/kolab_files/lib/kolab_files_engine.php                |   25 -
 plugins/kolab_files/localization/en_US.inc                    |   14 
 plugins/kolab_files/skins/larry/style.css                     |   61 ++-
 plugins/kolab_files/skins/larry/templates/compose_plugin.html |   22 -
 plugins/kolab_files/skins/larry/templates/filepreview.html    |   11 
 plugins/kolab_files/skins/larry/templates/files.html          |   59 ++-
 plugins/kolab_files/skins/larry/templates/message_plugin.html |   13 
 plugins/kolab_files/skins/larry/ui.js                         |   12 
 9 files changed, 267 insertions(+), 119 deletions(-)

New commits:
commit d1e3acf1ade7a66fa6a0eb42d83bd8229f91186d
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Thu Jun 12 12:55:34 2014 +0200

    Files: Accessibility improvements (#3087), Display dialogs from frames in main window.

diff --git a/plugins/kolab_files/kolab_files.js b/plugins/kolab_files/kolab_files.js
index ea80a55..0f922a7 100644
--- a/plugins/kolab_files/kolab_files.js
+++ b/plugins/kolab_files/kolab_files.js
@@ -30,22 +30,21 @@ window.rcmail && rcmail.addEventListener('init', function() {
     // mail compose
     if (rcmail.env.action == 'compose') {
       var elem = $('#compose-attachments > div'),
-        input = $('<input class="button" type="button">');
-
-      input.val(rcmail.gettext('kolab_files.fromcloud'))
-        .click(function() { kolab_files_selector_dialog(); })
-        .appendTo(elem);
+        input = $('<input class="button" type="button">')
+          .attr('tabindex', $('input', elem).attr('tabindex') || 0)
+          .val(rcmail.gettext('kolab_files.fromcloud'))
+          .click(function() { kolab_files_selector_dialog(); })
+          .appendTo(elem);
 
       if (rcmail.gui_objects.filelist) {
         rcmail.file_list = new rcube_list_widget(rcmail.gui_objects.filelist, {
           multiselect: true,
-//        draggable: true,
           keyboard: true,
           column_movable: false,
           dblclick_time: rcmail.dblclick_time
         });
-        rcmail.file_list.addEventListener('select', function(o) { kolab_files_list_select(o); });
-        rcmail.file_list.addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', e); });
+        rcmail.file_list.addEventListener('select', function(o) { kolab_files_list_select(o); })
+          .addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', e); });
 
         rcmail.gui_objects.filelist.parentNode.onmousedown = function(e){ return kolab_files_click_on_list(e); };
         rcmail.enable_command('files-sort', 'files-search', 'files-search-reset', true);
@@ -90,16 +89,16 @@ window.rcmail && rcmail.addEventListener('init', function() {
       rcmail.file_list.addEventListener('dragstart', function(o){ p.drag_start(o); });
       rcmail.file_list.addEventListener('dragmove', function(e){ p.drag_move(e); });
 */
-      rcmail.file_list.addEventListener('dblclick', function(o){ kolab_files_list_dblclick(o); });
-      rcmail.file_list.addEventListener('select', function(o){ kolab_files_list_select(o); });
-      rcmail.file_list.addEventListener('dragend', function(e){ kolab_files_drag_end(e); });
-      rcmail.file_list.addEventListener('column_replace', function(e){ kolab_files_set_coltypes(e); });
-      rcmail.file_list.addEventListener('listupdate', function(e){ rcmail.triggerEvent('listupdate', e); });
+      rcmail.file_list.addEventListener('dblclick', function(o) { kolab_files_list_dblclick(o); })
+        .addEventListener('select', function(o) { kolab_files_list_select(o); })
+        .addEventListener('keypress', function(o) { kolab_files_list_keypress(o); })
+        .addEventListener('dragend', function(e) { kolab_files_drag_end(e); })
+        .addEventListener('column_replace', function(e) { kolab_files_set_coltypes(e); })
+        .addEventListener('listupdate', function(e) { rcmail.triggerEvent('listupdate', e); });
 
-//      document.onmouseup = function(e){ return p.doc_mouse_up(e); };
-      rcmail.gui_objects.filelist.parentNode.onmousedown = function(e){ return kolab_files_click_on_list(e); };
+      rcmail.gui_objects.filelist.parentNode.onmousedown = function(e) { return kolab_files_click_on_list(e); };
 
-      rcmail.enable_command('menu-open', 'menu-save', 'files-sort', 'files-search', 'files-search-reset', true);
+      rcmail.enable_command('menu-open', 'menu-save', 'files-sort', 'files-search', 'files-search-reset', 'folder-create', true);
 
       rcmail.file_list.init();
       kolab_files_list_coltypes();
@@ -154,7 +153,7 @@ function kolab_files_token()
 {
   // consider the token from parent window more reliable (fresher) than in framed window
   // it's because keep-alive is not requested in frames
-  return (window.parent && parent.rcmail && parent.rcmail.env.files_token) || rcmail.env.files_token;
+  return window.parent && parent.rcmail && parent.rcmail.env.files_token ? parent.rcmail.env.files_token : rcmail.env.files_token;
 };
 
 // folder selection dialog
@@ -164,11 +163,20 @@ function kolab_directory_selector_dialog(id)
     input = $('#file-save-as-input'),
     form = $('#file-save-as'),
     list = $('#folderlistbox'),
-    buttons = {}, label = 'saveto';
+    buttons = {}, label = 'saveto',
+    win = window, fn;
 
   // attachment is specified
   if (id) {
-    var attach = $('#attach'+id), filename = attach.attr('title') || attach.text();
+    var attach = $('#attach' + id + '> a').first(),
+      filename = attach.attr('title');
+
+    if (!filename) {
+      attach = attach.clone();
+      $('.attachment-size', attach).remove();
+      filename = attach.text();
+    }
+
     form.show();
     dialog.addClass('saveas');
     input.val(filename);
@@ -186,6 +194,8 @@ function kolab_directory_selector_dialog(id)
     label = 'saveall';
   }
 
+  $('#foldercreatelink').attr('tabindex', 0);
+
   buttons[rcmail.gettext('kolab_files.save')] = function () {
     var lock = rcmail.set_busy(true, 'saving'),
       request = {
@@ -201,12 +211,20 @@ function kolab_directory_selector_dialog(id)
     }
 
     rcmail.http_post('plugin.kolab_files', request, lock);
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
+
   buttons[rcmail.gettext('kolab_files.cancel')] = function () {
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
 
+  if (!rcmail.env.folders_loaded) {
+    fn = function() {
+      file_api.folder_list();
+      rcmail.env.folders_loaded = true;
+    };
+  }
+
   // show dialog window
   kolab_dialog_show(dialog, {
     title: rcmail.gettext('kolab_files.' + label),
@@ -215,11 +233,14 @@ function kolab_directory_selector_dialog(id)
     minHeight: 300,
     height: 350,
     width: 300
-  });
+  }, fn);
 
-  if (!rcmail.env.folders_loaded) {
-    file_api.folder_list();
-    rcmail.env.folders_loaded = true;
+  // "enable" folder creation when dialog is displayed in parent window
+  if (rcmail.is_framed() && !parent.rcmail.folder_create) {
+    parent.rcmail.enable_command('folder-create', true);
+    parent.rcmail.folder_create = function() {
+      win.kolab_files_folder_create_dialog();
+    };
   }
 };
 
@@ -234,7 +255,7 @@ function kolab_files_selector_dialog()
       list.push($(this).data('file'));
     });
 
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
 
     if (list.length) {
       // display upload indicator and cancel button
@@ -252,8 +273,9 @@ function kolab_files_selector_dialog()
       });
     }
   };
+
   buttons[rcmail.gettext('kolab_files.cancel')] = function () {
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
 
   // show dialog window
@@ -270,8 +292,9 @@ function kolab_files_selector_dialog()
     file_api.folder_list();
     rcmail.env.files_loaded = true;
   }
-  else
+  else {
     rcmail.file_list.clear_selection();
+  }
 };
 
 function kolab_files_attach_menu_open(p)
@@ -306,10 +329,11 @@ function kolab_files_folder_create_dialog()
     folder += name;
 
     file_api.folder_create(folder);
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
+
   buttons[rcmail.gettext('kolab_files.cancel')] = function () {
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
 
   // show dialog window
@@ -358,10 +382,10 @@ function kolab_files_file_edit_dialog(file)
     // @TODO: now we only update filename
     if (name != file)
       file_api.file_rename(file, name);
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
   buttons[rcmail.gettext('kolab_files.cancel')] = function () {
-    dialog.dialog('destroy').hide();
+    kolab_dialog_close(this);
   };
 
   // Fix submitting form with Enter
@@ -374,11 +398,11 @@ function kolab_files_file_edit_dialog(file)
   });
 };
 
-function kolab_dialog_show(dialog, params)
+function kolab_dialog_show(content, params, onopen)
 {
   params = $.extend({
     modal: true,
-    resizable: !bw.ie6,
+    resizable: true,
     closeOnEscape: (!bw.ie6 && !bw.ie7),  // disabled for performance reasons
     minWidth: 400,
     minHeight: 300,
@@ -386,7 +410,36 @@ function kolab_dialog_show(dialog, params)
     height: 400
   }, params || {});
 
-  dialog.dialog(params).show();
+  // dialog close handler
+  params.close = function(e, ui) {
+    var elem, stack = rcmail.dialog_stack;
+
+    content.appendTo(document.body).hide();
+    $(this).parent().remove(); // remove dialog
+
+    // focus previously focused element (guessed)
+    stack.pop();
+    if (stack.length) {
+      elem = stack[stack.length-1].find('input[type!="hidden"]:not(:hidden):first');
+      if (!elem.length)
+        elem = stack[stack.length-1].parent().find('button:first');
+    }
+
+    (elem && elem.length ? elem : window).focus();
+  };
+
+  // display it as popup
+  var dialog = rcmail.show_popup_dialog('', params.title, params.buttons, params);
+
+  content.appendTo(dialog).show().find('input[type!="hidden"]:not(:hidden):first').focus();
+
+  if (onopen) onopen(content);
+
+  // save dialog reference, to handle focus when closing one of opened dialogs
+  if (!rcmail.dialog_stack)
+    rcmail.dialog_stack = [];
+
+  rcmail.dialog_stack.push(dialog);
 };
 
 // Handle form submit with Enter key, click first dialog button instead
@@ -396,6 +449,12 @@ function kolab_dialog_submit_handler()
   return false;
 };
 
+// Hides dialog
+function kolab_dialog_close(dialog)
+{
+  (rcmail.is_framed() ? window.parent : window).$(dialog).dialog('close');
+};
+
 // smart upload button
 function kolab_files_upload_input(button)
 {
@@ -407,7 +466,7 @@ function kolab_files_upload_input(button)
     file.css({top: (e.pageY - offset.top - 10) + 'px', left: (e.pageX - offset.left - 10) + 'px'});
   }
 
-  file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5, title: link.attr('title')})
+  file.attr({name: 'file[]', type: 'file', multiple: 'multiple', size: 5, title: link.attr('title'), tabindex: "-1"})
     .change(function() { rcmail.files_upload('#filesuploadform'); })
     .click(function() { setTimeout(function() { link.mouseleave(); }, 20); })
     // opacity:0 does the trick, display/visibility doesn't work
@@ -579,6 +638,17 @@ kolab_files_list_select = function(list)
   rcmail.enable_command('files-open', rcmail.env.viewer);
 };
 
+kolab_files_list_keypress = function(list)
+{
+  if (list.modkey == CONTROL_KEY)
+    return;
+
+  if (list.key_pressed == list.ENTER_KEY)
+    rcmail.command('files-open');
+  else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY)
+    rcmail.command('files-delete');
+};
+
 kolab_files_drag_end = function(e)
 {
   var folder = $('#files-folder-list li.droptarget').removeClass('droptarget');
@@ -791,6 +861,11 @@ rcube_webmail.prototype.files_set_quota = function(p)
   this.set_quota(p);
 };
 
+rcube_webmail.prototype.folder_create = function()
+{
+  kolab_files_folder_create_dialog();
+};
+
 
 /**********************************************************/
 /*********          Files API handler            **********/
@@ -850,6 +925,12 @@ function kolab_files_ui()
       list = $('<ul class="listing"></ul>'),
       collections = !rcmail.env.action.match(/^(preview|show)$/) ? ['audio', 'video', 'image', 'document'] : [];
 
+    // try parent window if the list element does not exist
+    // i.e. called from dialog in parent window
+    if (!elem.length && window.parent && parent.rcmail) {
+      elem = $('#files-folder-list', window.parent.document.body);
+    }
+
     elem.html('').append(list);
 
     this.env.folders = this.folder_list_parse(response.result);
@@ -868,7 +949,9 @@ function kolab_files_ui()
       if (f.virtual)
         row.addClass('virtual');
       else
-        row.click(function() { file_api.folder_select(i); })
+        row.attr('tabindex', 0)
+          .keypress(function(e) { if (e.which == 13 || e.which == 32) file_api.folder_select(i); })
+          .click(function() { file_api.folder_select(i); })
           .mouseenter(function() {
             if (rcmail.file_list && rcmail.file_list.drag_active && !$(this).hasClass('selected'))
               $(this).addClass('droptarget');
@@ -888,7 +971,7 @@ function kolab_files_ui()
     $.each(collections, function(i, n) {
       var row = $('<li class="mailbox collection ' + n + '"></li>');
 
-      row.attr('id', 'folder-collection-' + n)
+      row.attr({id: 'folder-collection-' + n, tabindex: 0})
         .append($('<span class="name"></span>').text(rcmail.gettext('kolab_files.collection_' + n)))
         .click(function() { file_api.folder_select(n, true); });
 
@@ -909,11 +992,17 @@ function kolab_files_ui()
 
   this.folder_select = function(folder, is_collection)
   {
-    var list = $('#files-folder-list > ul');
-
     if (rcmail.busy)
       return;
 
+    var list = $('#files-folder-list > ul');
+
+    // try parent window if the list element does not exist
+    // i.e. called from dialog in parent window
+    if (!list.length && window.parent && parent.rcmail) {
+      list = $('#files-folder-list > ul', window.parent.document.body);
+    }
+
     $('li.selected', list).removeClass('selected');
 
     rcmail.enable_command('files-list', true);
diff --git a/plugins/kolab_files/lib/kolab_files_engine.php b/plugins/kolab_files/lib/kolab_files_engine.php
index e48ccf8..978bef5 100644
--- a/plugins/kolab_files/lib/kolab_files_engine.php
+++ b/plugins/kolab_files/lib/kolab_files_engine.php
@@ -298,7 +298,7 @@ class kolab_files_engine
 
         $thead = '';
         foreach ($this->file_list_head($attrib, $a_show_cols) as $cell) {
-            $thead .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']);
+            $thead .= html::tag('th', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']);
         }
 
         return html::tag('table', $attrib,
@@ -332,14 +332,21 @@ class kolab_files_engine
             $a_sort_cols = $this->sort_cols;
 
         if (!empty($attrib['optionsmenuicon'])) {
-            $onclick = 'return ' . JS_OBJECT_NAME . ".command('menu-open', 'filelistmenu')";
-            if ($attrib['optionsmenuicon'] === true || $attrib['optionsmenuicon'] == 'true')
-                $list_menu = html::div(array('onclick' => $onclick, 'class' => 'listmenu',
-                    'id' => 'listmenulink', 'title' => $this->rc->gettext('listoptions')));
-            else
-                $list_menu = html::a(array('href' => '#', 'onclick' => $onclick),
-                    html::img(array('src' => $skin_path . $attrib['optionsmenuicon'],
-                        'id' => 'listmenulink', 'title' => $this->rc->gettext('listoptions'))));
+            $onclick = 'return ' . JS_OBJECT_NAME . ".command('menu-open', 'filelistmenu', this, event)";
+            $inner   = $this->rc->gettext('listoptions');
+
+            if (is_string($attrib['optionsmenuicon']) && $attrib['optionsmenuicon'] != 'true') {
+                $inner = html::img(array('src' => $skin_path . $attrib['optionsmenuicon'], 'alt' => $RCMAIL->gettext('listoptions')));
+            }
+
+            $list_menu = html::a(array(
+                'href'     => '#list-options',
+                'onclick'  => $onclick,
+                'class'    => 'listmenu',
+                'id'       => 'listmenulink',
+                'title'    => $this->rc->gettext('listoptions'),
+                'tabindex' => '0',
+            ), $inner);
         }
         else {
             $list_menu = '';
diff --git a/plugins/kolab_files/localization/en_US.inc b/plugins/kolab_files/localization/en_US.inc
index 1f6e618..b521d85 100644
--- a/plugins/kolab_files/localization/en_US.inc
+++ b/plugins/kolab_files/localization/en_US.inc
@@ -1,6 +1,7 @@
 <?php
 
 $labels['files'] = 'Files';
+$labels['filepreview'] = 'File preview';
 $labels['saveall'] = 'Save all to cloud...';
 $labels['saveto'] = 'Save to cloud...';
 $labels['saveas'] = 'Save as:';
@@ -67,4 +68,17 @@ $labels['fileoverwrite'] = 'Overwrite';
 $labels['fileoverwriteall'] = 'Overwrite all';
 $labels['filemoveconfirm'] = 'This action is going to overwrite the destination file: <b>$file</b>.';
 
+$labels['arialabelsearchform'] = 'Files search form';
+$labels['arialabelquicksearchbox'] = 'Search input';
+$labels['arialabellistoptions'] = 'Files list options';
+$labels['arialabelfolderoptions'] = 'Folder actions';
+$labels['arialabelfileeditform'] = 'File editing form';
+$labels['arialabelfoldercreateform'] = 'Folder creation form';
+$labels['arialabelfolderlist'] = 'Folder/Collection selection';
+$labels['arialabelfileselectdialog'] = 'File selection dialog';
+$labels['arialabelattachmentoptions'] = 'Attachment save options';
+$labels['arialabelfilesavedialog'] = 'File(s) saving dialog';
+$labels['arialabelfileprops'] = 'File properties';
+$labels['arialabelfilecontent'] = 'File content';
+
 ?>
diff --git a/plugins/kolab_files/skins/larry/style.css b/plugins/kolab_files/skins/larry/style.css
index d566a10..e75a5bb 100644
--- a/plugins/kolab_files/skins/larry/style.css
+++ b/plugins/kolab_files/skins/larry/style.css
@@ -53,7 +53,9 @@
 }
 
 #filestoolbar a.button.print {
-  background:  url(../../../../skins/larry/images/buttons.png) center -810px no-repeat;
+  background-image: url(../../../../skins/larry/images/buttons.png);
+  background-position: center -810px;
+  background-repeat: no-repeat;
 }
 
 #filestoolbar form {
@@ -152,7 +154,7 @@
   color: #aaa;
 }
 
-.filelist thead tr td {
+.filelist thead tr th {
   padding: 0;
 }
 
@@ -161,50 +163,52 @@
   height: 18px;
 }
 
-.filelist tr td.size {
+.filelist tr > .size {
   width: 80px;
   text-align: right;
 }
 
-.filelist thead tr td.size {
+.filelist thead tr > .size {
   text-align: left;
 }
 
-.filelist tr td.mtime {
+.filelist tr > .mtime {
   width: 125px;
 }
 
-.filelist tr td.options {
-  width: 26px;
+.filelist tr > .options {
+  width: 32px;
   cursor: pointer;
 }
 
-.filelist thead tr td.filename,
+.filelist thead tr th.filename,
 .filelist tbody tr td.filename {
   width: 99%;
   white-space: nowrap;
 }
 
-.filelist thead tr td.sortedASC a,
-.filelist thead tr td.sortedDESC a {
+.filelist thead tr th.sortedASC a,
+.filelist thead tr th.sortedDESC a {
   color: #004458;
   text-decoration: underline;
-  background: url(../../../../skins/larry/images/listicons.png) right -912px no-repeat;
+  background-image: url(../../../../skins/larry/images/listicons.png);
+  background-position: right -912px;
+  background-repeat: no-repeat;
 }
 
-.filelist thead tr td.sortedASC a {
+.filelist thead tr th.sortedASC a {
   background-position: right -944px;
 }
 
-.filelist td img {
+.filelist img {
   vertical-align: middle;
   display: inline-block;
 }
 
-.filelist tr td.options div.listmenu,
-.filelist tr td.flag span.flagged,
-.filelist tr td.flag span.unflagged,
-.filelist tr td.flag span.unflagged:hover {
+.filelist tr > .options a.listmenu,
+.filelist tr > .flag span.flagged,
+.filelist tr > .flag span.unflagged,
+.filelist tr > .flag span.unflagged:hover {
   display: inline-block;
   vertical-align: middle;
   height: 18px;
@@ -213,21 +217,26 @@
   background: url(../../../../skins/larry/images/listicons.png) -100px 0 no-repeat;
 }
 
-.filelist thead tr td.options div.listmenu {
-  background-position: 0 -976px;
-  cursor: pointer;
-  width: 26px;
+.filelist thead tr th.options {
+  padding: 0;
+  border-left: none;
 }
 
-.filelist thead tr td.options {
-  padding: 0 3px;
+.filelist thead tr th.options .listmenu {
+  background-position: 3px -970px;
+  cursor: pointer;
+  width: 24px;
+  height: 20px;
+  padding: 4px 4px 5px;
+  text-indent: -5000px;
 }
 
-.filelist thead tr td.options {
-  padding: 2px 3px;
+.filelist thead tr th.options .listmenu:focus {
+  outline: none;
+  background-color: rgba(73,180,210,0.7);
 }
 
-.filelist thead tr td:first-child {
+.filelist thead tr th:first-child {
   border-radius: 4px 0 0 0;
 }
 
diff --git a/plugins/kolab_files/skins/larry/templates/compose_plugin.html b/plugins/kolab_files/skins/larry/templates/compose_plugin.html
index 2c45869..613a24a 100644
--- a/plugins/kolab_files/skins/larry/templates/compose_plugin.html
+++ b/plugins/kolab_files/skins/larry/templates/compose_plugin.html
@@ -1,21 +1,27 @@
-<div id="files-compose-dialog" class="uidialog">
-    <div id="quicksearchbar" class="searchbox">
+<div id="files-compose-dialog" class="uidialog" role="dialog" aria-labelledby="aria-label-fileselect" aria-hidden="true">
+    <h2 id="aria-label-fileselect" class="voice"><roundcube:label name="kolab_files.arialabelfileselectdialog" /></h2>
+    <div id="quicksearchbar" class="searchbox" role="search" aria-labelledby="aria-label-searchform">
+        <h3 id="aria-label-searchform" class="voice"><roundcube:label name="kolab_files.arialabelsearchform" /></h3>
+        <label for="quicksearchbox" class="voice"><roundcube:label name="arialabelquicksearchbox" /></label>
+        <roundcube:button name="filesearchmenulink" id="filesearchmenulink" class="iconbutton searchoptions" onclick="return UI.toggle_popup('filesearchmenu', event)" title="searchmod"  label="options" aria-haspopup="true" aria-expanded="false" aria-owns="filesearchmenu-menu" />
         <roundcube:object name="file-search-form" id="filesearchbox" />
-        <roundcube:button name="filesearchmenulink" id="filesearchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('filesearchmenu');return false" title="searchmod" content=" " />
         <roundcube:button command="files-search-reset" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
     </div>
 
-    <div id="folderlistbox" class="uibox listbox">
+    <div id="folderlistbox" class="uibox listbox" role="navigation" aria-labelledby="aria-label-folderlist">
+        <h3 id="aria-label-folderlist" class="voice"><roundcube:label name="kolab_files.arialabelfolderlist" /></h3>
         <div id="files-folder-list" class="scroller"></div>
     </div>
 
     <div id="filelistcontainer" class="boxlistcontent uibox">
-        <roundcube:object name="filelist" id="filelist" class="records-table filelist sortheader fixedheader" />
+        <h3 id="aria-label-filelist" class="voice"><roundcube:label name="arialabelfilelist" /></h3>
+        <roundcube:object name="filelist" id="filelist" class="records-table filelist sortheader fixedheader" aria-labelledby="aria-label-filelist" />
     </div>
 </div>
 
-<div id="filesearchmenu" class="popupmenu" style="z-index: 2000">
-    <ul class="toolbarmenu">
-        <li><label><input type="checkbox" name="all_folders" value="1" id="search_all_folders" /> <span><roundcube:label name="kolab_files.allfolders" /></span></label></li>
+<div id="filesearchmenu" class="popupmenu" style="z-index: 2000" data-editable="true" aria-hidden="true">
+    <h4 id="aria-label-searchmenu" class="voice"><roundcube:label name="searchmod" /></h4>
+    <ul id="filesearchmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-searchmenu">
+        <li role="menuitem"><label><input type="checkbox" name="all_folders" value="1" id="search_all_folders" /> <span><roundcube:label name="kolab_files.allfolders" /></span></label></li>
     </ul>
 </div>
diff --git a/plugins/kolab_files/skins/larry/templates/filepreview.html b/plugins/kolab_files/skins/larry/templates/filepreview.html
index 1ab6190..a0b5139 100644
--- a/plugins/kolab_files/skins/larry/templates/filepreview.html
+++ b/plugins/kolab_files/skins/larry/templates/filepreview.html
@@ -9,10 +9,12 @@
 
 <roundcube:include file="/includes/header.html" />
 
-
 <div id="mainscreen">
 
-<div id="filestoolbar" class="toolbar">
+<h1 class="voice"><roundcube:label name="kolab_files.filepreview" /></h1>
+
+<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
+<div id="filestoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
     <roundcube:button command="files-get" type="link" class="button get disabled" classAct="button get" classSel="button get pressed" label="kolab_files.get" title="kolab_files.getfile" />
     <roundcube:button command="files-edit" type="link" class="button edit disabled" classAct="button edit" classSel="button edit pressed" label="kolab_files.edit" title="kolab_files.editfile" />
     <roundcube:button command="files-save" type="link" class="button save disabled" classAct="button save" classSel="button save pressed" label="kolab_files.save" title="kolab_files.savefile" style="display:none" />
@@ -20,13 +22,14 @@
     <roundcube:button command="files-print" type="link" class="button print disabled" classAct="button print" classSel="button print pressed" label="print" title="kolab_files.printfile" />
 </div>
 
-<div id="fileinfobox" class="uibox listbox">
+<h2 id="aria-label-fileprops" class="voice"><roundcube:label name="kolab_files.arialabelfileprops" /></h2>
+<div id="fileinfobox" class="uibox listbox" aria-labelledby="aria-label-toolbar">
     <roundcube:object name="fileinfobox" id="fileinfo" class="listing" />
 </div>
 
 <div id="filecontent" class="uibox">
     <div class="iframebox">
-        <roundcube:object name="filepreviewframe" id="fileframe" frameborder="0" />
+        <roundcube:object name="filepreviewframe" id="fileframe" frameborder="0" title="kolab_files.arialabelfilecontent" />
     </div>
 </div>
 
diff --git a/plugins/kolab_files/skins/larry/templates/files.html b/plugins/kolab_files/skins/larry/templates/files.html
index e3af092..e6e2500 100644
--- a/plugins/kolab_files/skins/larry/templates/files.html
+++ b/plugins/kolab_files/skins/larry/templates/files.html
@@ -11,7 +11,10 @@
 
 <div id="mainscreen">
 
-<div id="filestoolbar" class="toolbar">
+<h1 class="voice"><roundcube:label name="kolab_files.files" /></h1>
+
+<div id="filestoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
+    <h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
     <form id="filesuploadform">
         <roundcube:button command="files-upload" type="link" class="button upload disabled" classAct="button upload" classSel="button upload pressed" label="kolab_files.upload" title="kolab_files.uploadfile" />
     </form>
@@ -20,50 +23,59 @@
     <roundcube:button command="files-delete" type="link" class="button delete disabled" classAct="button delete" classSel="button delete pressed" label="delete" title="kolab_files.deletefile" />
 </div>
 
-<div id="quicksearchbar" class="quicksearchbox">
+<div id="quicksearchbar" class="quicksearchbox" role="search" aria-labelledby="aria-label-searchform">
+    <h2 id="aria-label-searchform" class="voice"><roundcube:label name="kolab_files.arialabelsearchform" /></h2>
+    <label for="quicksearchbox" class="voice"><roundcube:label name="arialabelquicksearchbox" /></label>
+    <roundcube:button name="filesearchmenulink" id="filesearchmenulink" class="iconbutton searchoptions" onclick="return UI.toggle_popup('filesearchmenu', event)" title="searchmod" label="options" aria-haspopup="true" aria-expanded="false" aria-owns="filesearchmenu-menu" />
     <roundcube:object name="file-search-form" id="quicksearchbox" />
-    <roundcube:button name="filesearchmenulink" id="filesearchmenulink" class="iconbutton searchoptions" onclick="UI.show_popup('filesearchmenu');return false" title="searchmod" content=" " />
-    <roundcube:button command="files-search-reset" id="searchreset" class="iconbutton reset" title="resetsearch" content=" " />
+    <roundcube:button command="files-search-reset" id="searchreset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
 </div>
 
-<div id="folderlistbox" class="uibox listbox">
+<div id="folderlistbox" class="uibox listbox" role="navigation" aria-labelledby="aria-label-folderlist">
+    <h2 id="aria-label-folderlist" class="voice"><roundcube:label name="kolab_files.arialabelfolderlist" /></h2>
     <div id="files-folder-list" class="scroller withfooter">
     </div>
     <div id="folderlist-footer" class="boxfooter">
-        <roundcube:button name="folder-create" type="link" title="kolab_files.foldercreate" class="listbutton add" classAct="listbutton add" innerClass="inner" content="+" onclick="kolab_files_folder_create_dialog()" /><roundcube:button name="folderoptions" id="folderoptionslink" type="link" title="moreactions" class="listbutton groupactions" onclick="UI.show_popup('folderoptions', undefined, {above: 1});return false" innerClass="inner" content="⚙" />
+        <roundcube:button command="folder-create" type="link" title="kolab_files.foldercreate" class="listbutton add" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="folderoptions" id="folderoptionslink" type="link" title="moreactions" class="listbutton groupactions" onclick="return UI.toggle_popup('folderoptions', event)" innerClass="inner" content="⚙" aria-haspopup="true" aria-expanded="false" aria-owns="folderoptionsmenu" />
         <roundcube:if condition="env:files_quota" />
+            <span class="voice"><roundcube:label name="quota"></span>
             <roundcube:object name="filequotadisplay" id="quotadisplay" class="countdisplay" display="text" />
         <roundcube:endif />
     </div>
 </div>
 
 <div id="filelistcontainer" class="uibox">
+    <h2 id="aria-label-filelist" class="voice"><roundcube:label name="arialabelfilelist" /></h2>
     <div id="filelistbox" class="boxlistcontent">
-        <roundcube:object name="filelist" id="filelist" class="records-table filelist sortheader fixedheader" optionsmenuIcon="true" />
+        <roundcube:object name="filelist" id="filelist" class="records-table filelist sortheader fixedheader" optionsmenuIcon="true" aria-labelledby="aria-label-filelist" />
     </div>
 </div>
 
 </div>
 
-<div id="folderoptions" class="popupmenu">
-    <ul id="folderoptionsmenu" class="toolbarmenu">
+<div id="folderoptions" class="popupmenu" data-editable="true" aria-hidden="true">
+    <h3 id="aria-label-folderoptions" class="voice"><roundcube:label name="kolab_files.folderoptions" /></h3>
+    <ul id="folderoptionsmenu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-folderoptions">
 <!--
-        <li><roundcube:button command="files-folder-edit" label="edit" classAct="active" /></li>
+        <li role="menuitem"><roundcube:button command="files-folder-edit" label="edit" classAct="active" /></li>
 -->
-        <li><roundcube:button command="files-folder-delete" label="delete" classAct="active" /></li>
-        <li><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li>
+        <li role="menuitem"><roundcube:button command="files-folder-delete" label="delete" classAct="active" /></li>
+        <li role="menuitem"><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li>
         <roundcube:container name="filesfolderoptions" id="folderoptionsmenu" />
     </ul>
 </div>
 
-<div id="files-folder-create-dialog">
+<div id="files-folder-create-dialog" role="dialog" aria-labelledby="aria-label-foldercreateform" aria-hidden="true">
+    <h3 id="aria-label-foldercreateform" class="voice"><roundcube:label name="kolab_files.arialabelfoldercreateform" /></h3>
     <roundcube:object name="folder-create-form" />
 </div>
-<div id="files-file-edit-dialog">
+<div id="files-file-edit-dialog" role="dialog" aria-labelledby="aria-label-fileeditform" aria-hidden="true">
+    <h3 id="aria-label-fileeditform" class="voice"><roundcube:label name="kolab_files.arialabelfileeditform" /></h3>
     <roundcube:object name="file-edit-form" />
 </div>
 
-<div id="listoptions" class="propform popupdialog">
+<div id="listoptions" class="propform popupdialog" data-editable="true" role="dialog" aria-labelledby="aria-label-listoptions" aria-hidden="true">
+    <h3 id="aria-label-listoptions" class="voice"><roundcube:label name="kolab_files.arialabellistoptions" /></h3>
 <roundcube:if condition="!in_array('kolab_files_list_cols', (array)config:dont_override)" />
     <fieldset class="floating">
         <legend><roundcube:label name="listcolumns" /></legend>
@@ -97,20 +109,21 @@
     <br style="clear:both" />
     <div class="formbuttons">
         <roundcube:button command="menu-save" id="listmenusave" type="input" class="button mainaction" label="save" />
-        <roundcube:button command="menu-open" id="listmenucancel" type="input" class="button" label="cancel" />
+        <roundcube:button command="menu-close" prop="filelistmenu" id="listmenucancel" type="input" class="button" label="cancel" />
     </div>
 </div>
 
-<div id="dragfilemenu" class="popupmenu">
-    <ul class="toolbarmenu">
-        <li><roundcube:button command="files-move" onclick="return kolab_files_drag_menu_action('files-move')" label="move" classAct="active" /></li>
-        <li><roundcube:button command="files-copy" onclick="return kolab_files_drag_menu_action('files-copy')" label="copy" classAct="active" /></li>
+<div id="dragfilemenu" class="popupmenu" aria-hidden="true">
+    <ul class="toolbarmenu" role="menu">
+        <li role="menuitem"><roundcube:button command="files-move" onclick="return kolab_files_drag_menu_action('files-move')" label="move" classAct="active" /></li>
+        <li role="menuitem"><roundcube:button command="files-copy" onclick="return kolab_files_drag_menu_action('files-copy')" label="copy" classAct="active" /></li>
     </ul>
 </div>
 
-<div id="filesearchmenu" class="popupmenu">
-    <ul class="toolbarmenu">
-        <li><label><input type="checkbox" name="all_folders" value="1" id="search_all_folders" /> <span><roundcube:label name="kolab_files.allfolders" /></span></label></li>
+<div id="filesearchmenu" class="popupmenu" data-editable="true" aria-hidden="true">
+    <h3 id="aria-label-searchmenu" class="voice"><roundcube:label name="searchmod" /></h3>
+    <ul id="filesearchmenu-menu" class="toolbarmenu" role="menu" aria-labelledby="aria-label-searchmenu">
+        <li role="menuitem"><label><input type="checkbox" name="all_folders" value="1" id="search_all_folders" /> <span><roundcube:label name="kolab_files.allfolders" /></span></label></li>
     </ul>
 </div>
 
diff --git a/plugins/kolab_files/skins/larry/templates/message_plugin.html b/plugins/kolab_files/skins/larry/templates/message_plugin.html
index a3e5ad1..eeb78fd 100644
--- a/plugins/kolab_files/skins/larry/templates/message_plugin.html
+++ b/plugins/kolab_files/skins/larry/templates/message_plugin.html
@@ -1,16 +1,21 @@
-<div id="files-dialog" class="uidialog">
+<div id="files-dialog" class="uidialog" data-editable="true" role="dialog" aria-labelledby="aria-label-filesavedialog" aria-hidden="true">
+    <h3 id="aria-label-filesavedialog" class="voice"><roundcube:label name="kolab_files.arialabelfilesavedialog" /></h3>
     <div id="file-save-as">
         <label for="file-save-as-input"><roundcube:label name="kolab_files.saveas" /></label>
         <input id="file-save-as-input" type="text" value="">
     </div>
-    <div id="folderlistbox" class="uibox listbox">
+    <div id="folderlistbox" class="uibox listbox" role="navigation" aria-labelledby="aria-label-folderlist">
+        <h3 id="aria-label-folderlist" class="voice"><roundcube:label name="kolab_files.arialabelfolderlist" /></h3>
         <div id="files-folder-list" class="scroller withfooter"></div>
         <div id="folderlist-footer" class="boxfooter">
-            <roundcube:button name="foldercreatelink" id="foldercreatelink" type="link" onclick="kolab_files_folder_create_dialog()" title="createfolder" class="listbutton add" classAct="listbutton add" innerClass="inner" content="+" />
+            <roundcube:button command="folder-create" name="foldercreatelink" id="foldercreatelink" type="link" title="createfolder" class="listbutton add" classAct="listbutton add" innerClass="inner" content="+" />
         </div>
     </div>
 </div>
-<div id="files-folder-create-dialog">
+
+<div id="files-folder-create-dialog" role="dialog" aria-labelledby="aria-label-foldercreateform" aria-hidden="true">
+    <h3 id="aria-label-foldercreateform" class="voice"><roundcube:label name="kolab_files.arialabelfoldercreateform" /></h3>
     <roundcube:object name="folder-create-form" />
 </div>
+
 <script src="plugins/kolab_files/skins/larry/ui.js" type="text/javascript"></script>
diff --git a/plugins/kolab_files/skins/larry/ui.js b/plugins/kolab_files/skins/larry/ui.js
index aa2c30f..3d5ba0d 100644
--- a/plugins/kolab_files/skins/larry/ui.js
+++ b/plugins/kolab_files/skins/larry/ui.js
@@ -13,6 +13,7 @@ function kolab_files_ui_init()
   $(document).ready(function() {
     rcmail.addEventListener('menu-open', kolab_files_show_listoptions);
     rcmail.addEventListener('menu-save', kolab_files_save_listoptions);
+    rcmail.addEventListener('menu-close', kolab_files_show_listoptions);
     rcmail.addEventListener('setquota', kolab_files_update_quota);
 
     var menu = $('#dragfilemenu');
@@ -24,7 +25,6 @@ function kolab_files_ui_init()
     menu = $('#filesearchmenu');
     if (menu.length) {
       rcmail.gui_object('file_searchmenu', 'filesearchmenu');
-      UI.add_popup('filesearchmenu', {sticky: 1});
     }
   });
 
@@ -45,8 +45,12 @@ function kolab_files_update_quota(p)
     return UI.update_quota(p);
 };
 
-function kolab_files_show_listoptions()
+function kolab_files_show_listoptions(p)
 {
+  if (!p || p.name != 'filelistmenu') {
+    return;
+  }
+
   var $dialog = $('#listoptions');
 
   // close the dialog
@@ -69,10 +73,8 @@ function kolab_files_show_listoptions()
     modal: true,
     resizable: false,
     closeOnEscape: true,
+    close: function() { rcmail.file_list.focus(); },
     title: null,
-    close: function() {
-      $dialog.dialog('destroy').hide();
-    },
     minWidth: 400,
     width: $dialog.width()+20
   }).show();





More information about the commits mailing list