1. Prepare core and Larry skin for improved accessibility
2. Implement full keyboard navigation in main mail view
| | |
| | | a.iconbutton, |
| | | a.deletebutton, |
| | | .boxpagenav a.icon, |
| | | a.button span.icon, |
| | | .pagenav a.button span.inner, |
| | | .boxfooter .listbutton .inner, |
| | | .attachmentslist li a.delete, |
| | |
| | | $attrib['alt'] = html::quote($this->app->gettext($attrib['alt'], $attrib['domain'])); |
| | | } |
| | | |
| | | // set accessibility attributes |
| | | if (!$attrib['role']) { |
| | | $attrib['role'] = 'button'; |
| | | } |
| | | if (!empty($attrib['class']) && !empty($attrib['classact']) || !empty($attrib['imagepas']) && !empty($attrib['imageact'])) { |
| | | $attrib['tabindex'] = '-1'; // disable button by default |
| | | $attrib['aria-disabled'] = 'true'; |
| | | } |
| | | |
| | | // set title to alt attribute for IE browsers |
| | | if ($this->browser->ie && !$attrib['title'] && $attrib['alt']) { |
| | | $attrib['title'] = $attrib['alt']; |
| | |
| | | this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', |
| | | 'compose', 'undo', 'about', 'switch-task', 'menu-open', 'menu-save', true); |
| | | |
| | | // set active task button |
| | | this.set_button(this.task, 'sel'); |
| | | |
| | | if (this.env.permaurl) |
| | | this.enable_command('permaurl', 'extwin', true); |
| | | |
| | |
| | | }); |
| | | |
| | | document.onmouseup = function(e){ return ref.doc_mouse_up(e); }; |
| | | this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return ref.click_on_list(e); }; |
| | | this.gui_objects.messagelist.parentNode.onclick = function(e){ return ref.click_on_list(e || window.event); }; |
| | | |
| | | this.enable_command('toggle_status', 'toggle_flag', 'sort', true); |
| | | this.enable_command('set-listmode', this.env.threads && !this.is_multifolder_listing()); |
| | |
| | | this.gui_objects.qsearchbox.blur(); |
| | | |
| | | if (this.message_list) |
| | | this.message_list.focus(); |
| | | this.message_list.focus(e); |
| | | else if (this.contact_list) |
| | | this.contact_list.focus(); |
| | | this.contact_list.focus(e); |
| | | |
| | | return true; |
| | | }; |
| | |
| | | |
| | | // build subject link |
| | | if (cols.subject) { |
| | | var action = flags.mbox == this.env.drafts_mailbox ? 'compose' : 'show'; |
| | | var uid_param = flags.mbox == this.env.drafts_mailbox ? '_draft_uid' : '_uid'; |
| | | cols.subject = '<a href="./?_task=mail&_action='+action+'&_mbox='+urlencode(flags.mbox)+'&'+uid_param+'='+urlencode(uid)+'"'+ |
| | | ' onclick="return rcube_event.cancel(event)" onmouseover="rcube_webmail.long_subject_title(this,'+(message.depth+1)+')"><span>'+cols.subject+'</span></a>'; |
| | | var action = flags.mbox == this.env.drafts_mailbox ? 'compose' : 'show', |
| | | uid_param = flags.mbox == this.env.drafts_mailbox ? '_draft_uid' : '_uid', |
| | | query = { _mbox: flags.mbox }; |
| | | query[uid_param] = uid; |
| | | cols.subject = '<a href="' + this.url(action, query) + '" onclick="return rcube_event.keyboard_only(event)"' + |
| | | ' onmouseover="rcube_webmail.long_subject_title(this,'+(message.depth+1)+')" tabindex="-1"><span>'+cols.subject+'</span></a>'; |
| | | } |
| | | |
| | | // add each submitted col |
| | |
| | | init_button(cmd, this.buttons[cmd][i]); |
| | | } |
| | | } |
| | | |
| | | // set active task button |
| | | this.set_button(this.task, 'sel'); |
| | | }; |
| | | |
| | | // set button to a specific state |
| | |
| | | button = a_buttons[n]; |
| | | obj = document.getElementById(button.id); |
| | | |
| | | if (!obj) |
| | | if (!obj || button.status == state) |
| | | continue; |
| | | |
| | | // get default/passive setting of the button |
| | |
| | | obj.disabled = state == 'pas'; |
| | | } |
| | | else if (button.type == 'uibutton') { |
| | | button.status = state; |
| | | $(obj).button('option', 'disabled', state == 'pas'); |
| | | } |
| | | else { |
| | | $(obj) |
| | | .attr('tabindex', state == 'pas' || state == 'sel' ? '-1' : '0') |
| | | .attr('aria-disabled', state == 'pas' || state == 'sel' ? 'true' : 'false'); |
| | | } |
| | | } |
| | | }; |
| | |
| | | this.enable_command('set-listmode', this.env.threads && !is_multifolder); |
| | | |
| | | if ((response.action == 'list' || response.action == 'search') && this.message_list) { |
| | | this.message_list.focus(); |
| | | this.msglist_select(this.message_list); |
| | | this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount }); |
| | | } |
| | |
| | | return false; |
| | | }, |
| | | |
| | | /** |
| | | * Determine whether the given event was trigered from keyboard |
| | | */ |
| | | is_keyboard: function(e) |
| | | { |
| | | return e && ( |
| | | (e.mozInputSource && e.mozInputSource == e.MOZ_SOURCE_KEYBOARD) || |
| | | (!e.pageX && (e.pageY || 0) <= 0 && !e.clientX && (e.clientY || 0) <= 0) |
| | | ); |
| | | }, |
| | | |
| | | /** |
| | | * Accept event if triggered from keyboard action (e.g. <Enter>) |
| | | */ |
| | | keyboard_only: function(e) |
| | | { |
| | | console.log(e); |
| | | return rcube_event.is_keyboard(e) ? true : rcube_event.cancel(e); |
| | | }, |
| | | |
| | | touchevent: function(e) |
| | | { |
| | | return { pageX:e.pageX, pageY:e.pageY, offsetX:e.pageX - e.target.offsetLeft, offsetY:e.pageY - e.target.offsetTop, target:e.target, istouch:true }; |
| | |
| | | this.rows = {}; |
| | | this.rowcount = 0; |
| | | |
| | | var r, len, rows = this.tbody.childNodes; |
| | | var r, len, rows = this.tbody.childNodes, me = this; |
| | | |
| | | for (r=0, len=rows.length; r<len; r++) { |
| | | this.rowcount += this.init_row(rows[r]) ? 1 : 0; |
| | |
| | | this.frame = this.list.parentNode; |
| | | |
| | | // set body events |
| | | if (this.keyboard) |
| | | 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:absolute; top:-1000px') |
| | | .html('Select List') |
| | | .insertAfter(this.list) |
| | | .on('focus', function(e){ me.focus(e); }) |
| | | .on('blur', function(e){ me.blur(e); }); |
| | | } |
| | | } |
| | | |
| | | return this; |
| | |
| | | |
| | | if (this.fixed_header) { // copy (modified) fixed header back to the actual table |
| | | $(this.list.tHead).replaceWith($(this.fixed_header).find('thead').clone()); |
| | | $(this.list.tHead).find('tr td').attr('style', ''); // remove fixed widths |
| | | $(this.list.tHead).find('tr td').attr('style', '').find('a.sortcol').attr('tabindex', '-1'); // remove fixed widths |
| | | } |
| | | else if (!bw.touch && this.list.className.indexOf('fixedheader') >= 0) { |
| | | else if (!bw.touch && this.list.className.indexOf('fixedheader') >= 0 && 0) { |
| | | this.init_fixed_header(); |
| | | } |
| | | |
| | |
| | | else { |
| | | $(this.fixed_header).find('thead').replaceWith(clone); |
| | | } |
| | | |
| | | // avoid scrolling header links being focused |
| | | $(this.list.tHead).find('a.sortcol').attr('tabindex', '-1'); |
| | | |
| | | // set tabindex to fixed header sort links |
| | | clone.find('a.sortcol').attr('tabindex', '0'); |
| | | |
| | | this.thead = clone.get(0); |
| | | this.resize(); |
| | |
| | | |
| | | if (sel) |
| | | this.clear_selection(); |
| | | else |
| | | this.last_selected = 0; |
| | | |
| | | // reset scroll position (in Opera) |
| | | if (this.frame) |
| | |
| | | */ |
| | | focus: function(e) |
| | | { |
| | | if (this.focused) |
| | | return; |
| | | |
| | | var n, id; |
| | | this.focused = true; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | if (e) |
| | | rcube_event.cancel(e); |
| | | |
| | | // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) |
| | | // It looks that window.focus() does the job for all browsers, but not Firefox (#1489058) |
| | | $('iframe,:focus:not(body)').blur(); |
| | | window.focus(); |
| | | // We now fix this by explicitly assigning focus to a dedicated link element |
| | | this.focus_elem.focus(); |
| | | |
| | | if (e || (e = window.event)) |
| | | rcube_event.cancel(e); |
| | | $(this.list).addClass('focus'); |
| | | |
| | | // set internal focus pointer to first row |
| | | if (!this.last_selected) |
| | | this.select_first(CONTROL_KEY); |
| | | }, |
| | | |
| | | |
| | | /** |
| | | * remove focus from the list |
| | | */ |
| | | blur: function() |
| | | blur: function(e) |
| | | { |
| | | var n, id; |
| | | this.focused = false; |
| | |
| | | $(this.rows[id].obj).removeClass('selected focused').addClass('unfocused'); |
| | | } |
| | | } |
| | | |
| | | $(this.list).removeClass('focus'); |
| | | }, |
| | | |
| | | |
| | |
| | | this.selection = []; |
| | | } |
| | | |
| | | if (num_select && !this.selection.length && !no_event) |
| | | if (num_select && !this.selection.length && !no_event) { |
| | | this.triggerEvent('select'); |
| | | this.last_selected = 0; |
| | | } |
| | | }, |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | if (new_row) { |
| | | // simulate ctr-key if no rows are selected |
| | | if (!mod_key && !this.selection.length) |
| | | mod_key = CONTROL_KEY; |
| | | |
| | | this.select_row(new_row.uid, mod_key, false); |
| | | this.scrollto(new_row.uid); |
| | | } |
| | | else if (!new_row && !selected_row) { |
| | | // select the first row if none selected yet |
| | | this.select_first(CONTROL_KEY); |
| | | } |
| | | |
| | | return false; |
| | | }, |
| | |
| | | } |
| | | }); |
| | | |
| | | container.attr('role', 'tree'); |
| | | |
| | | |
| | | /////// private methods |
| | | |
| | |
| | | selection = node.id; |
| | | } |
| | | |
| | | // declare list item as treeitem |
| | | li.attr('role', 'treeitem'); |
| | | |
| | | result.push(node); |
| | | indexbyid[node.id] = node; |
| | | }) |
| | |
| | | |
| | | public static $doctype = 'xhtml'; |
| | | public static $lc_tags = true; |
| | | public static $common_attrib = array('id','class','style','title','align','unselectable'); |
| | | public static $common_attrib = array('id','class','style','title','align','unselectable','tabindex','role'); |
| | | public static $containers = array('iframe','div','span','p','h1','h2','h3','ul','form','textarea','table','thead','tbody','tr','th','td','style','script'); |
| | | |
| | | |
| | |
| | | // ignore not allowed attributes |
| | | if (!empty($allowed)) { |
| | | $is_data_attr = @substr_compare($key, 'data-', 0, 5) === 0; |
| | | if (!isset($allowed_f[$key]) && (!$is_data_attr || !isset($allowed_f['data-*']))) { |
| | | $is_aria_attr = @substr_compare($key, 'aria-', 0, 5) === 0; |
| | | if (!$is_aria_attr && !isset($allowed_f[$key]) && (!$is_data_attr || !isset($allowed_f['data-*']))) { |
| | | continue; |
| | | } |
| | | } |
| | |
| | | <div id="header"> |
| | | <div id="header" role="banner"> |
| | | <div id="topline"> |
| | | <div class="topleft"> |
| | | <roundcube:container name="topline-left" id="topline-left" /> |
| | |
| | | |
| | | <roundcube:if condition="!env:extwin && !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" /> |
| | |
| | | <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'" /> |
| | |
| | | <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> |
| | |
| | | padding-right: 36px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox > a:focus, |
| | | #mailboxlist li.mailbox.selected > a { |
| | | background-position: 6px -21px; |
| | | } |
| | |
| | | background-position: 6px -189px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.inbox > a:focus, |
| | | #mailboxlist li.mailbox.inbox.selected > a { |
| | | background-position: 6px -213px; |
| | | } |
| | |
| | | background-position: 6px -238px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.drafts > a:focus, |
| | | #mailboxlist li.mailbox.drafts.selected > a { |
| | | background-position: 6px -262px; |
| | | } |
| | |
| | | background-position: 6px -286px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.sent > a:focus, |
| | | #mailboxlist li.mailbox.sent.selected > a { |
| | | background-position: 6px -310px; |
| | | } |
| | |
| | | background-position: 6px -334px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.junk > a:focus, |
| | | #mailboxlist li.mailbox.junk.selected > a { |
| | | background-position: 6px -358px; |
| | | } |
| | |
| | | background-position: 6px -382px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.trash > a:focus, |
| | | #mailboxlist li.mailbox.trash.selected > a { |
| | | background-position: 6px -406px; |
| | | } |
| | |
| | | background-position: 6px -1924px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.trash.empty > a:focus, |
| | | #mailboxlist li.mailbox.trash.empty.selected > a { |
| | | background-position: 6px -1948px; |
| | | } |
| | |
| | | background-position: 6px -1699px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox.archive > a:focus, |
| | | #mailboxlist li.mailbox.archive.selected > a { |
| | | background-position: 6px -1723px; |
| | | } |
| | |
| | | background-position: 23px -238px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox ul li.drafts > a:focus, |
| | | #mailboxlist li.mailbox ul li.drafts.selected > a { |
| | | background-position: 23px -262px; |
| | | } |
| | |
| | | background-position: 23px -286px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox ul li.sent > a:focus, |
| | | #mailboxlist li.mailbox ul li.sent.selected > a { |
| | | background-position: 23px -310px; |
| | | } |
| | |
| | | background-position: 23px -334px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox ul li.junk > a:focus, |
| | | #mailboxlist li.mailbox ul li.junk.selected > a { |
| | | background-position: 23px -358px; |
| | | } |
| | |
| | | background-position: 23px -382px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox ul li.trash > a:focus, |
| | | #mailboxlist li.mailbox ul li.trash.selected > a { |
| | | background-position: 23px -406px; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | background-position: 23px -1699px; |
| | | } |
| | | |
| | | #mailboxlist li.mailbox ul li.archive > a:focus, |
| | | #mailboxlist li.mailbox ul li.archive.selected > a { |
| | | background-position: 23px -1723px; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | .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 { |
| | |
| | | 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; |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | 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 { |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | /* 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; |
| | | } |
| | | |
| | |
| | | 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); |
| | |
| | | } |
| | | |
| | | |
| | | 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 { |
| | |
| | | |
| | | .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'] { |
| | |
| | | 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, |
| | |
| | | <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"> |
| | |
| | | |
| | | </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" /> |
| | | ● <a href="<roundcube:var name='config:support_url' />" target="_blank" class="support-link"><roundcube:label name="support" /></a> |
| | |
| | | <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> |
| | |
| | | |
| | | <!-- 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> |
| | | |
| | |
| | | <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="⚙" /> |
| | | <roundcube:button name="mailboxmenulink" id="mailboxmenulink" type="link" title="folderactions" class="listbutton groupactions" onclick="UI.toggle_popup('mailboxmenu',event);return false" innerClass="inner" content="⚙" /> |
| | | <roundcube:if condition="env:quota" /> |
| | | <roundcube:object name="quotaDisplay" id="quotadisplay" class="countdisplay" display="text" /> |
| | | <roundcube:endif /> |
| | |
| | | |
| | | </div> |
| | | |
| | | <div id="mailview-right"> |
| | | <div id="mailview-right" role="main"> |
| | | |
| | | <roundcube:if condition="config:preview_pane == true" /> |
| | | <div id="mailview-top" class="uibox"> |
| | |
| | | </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" /> |
| | | <a href="#threads" id="threadselectmenulink" class="menuselector" onclick="UI.show_popup('threadselectmenu');return false"><span class="handle"><roundcube:label name="threads" /></span></a> |
| | | <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> |
| | | |
| | |
| | | |
| | | <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 --> |
| | |
| | | var mailviewsplit; |
| | | var compose_headers = {}; |
| | | var prefs; |
| | | var focused_popup; |
| | | var popup_keyboard_active = false; |
| | | |
| | | // export public methods |
| | | this.set = setenv; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | |
| | | $(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 |
| | |
| | | /** |
| | | * 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); |
| | |
| | | /** |
| | | * Show/hide a specific popup menu |
| | | */ |
| | | function show_popupmenu(popup, show) |
| | | function show_popupmenu(popup, show, keyboard) |
| | | { |
| | | var obj = popups[popup], |
| | | config = popupconfig[popup], |
| | |
| | | |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | |
| | | 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'); |
| | | } |
| | | } |
| | | |