Commit 48687b57 authored by Thomas Greiner's avatar Thomas Greiner

Issue 2409 - Improved accessibility of tabs in options page

parent c1e08b3e
......@@ -37,35 +37,41 @@
<p class="i18n_options_page_header_1"></p>
<h1 class="i18n_options_page_header_2"></h1>
</header>
<nav>
<ul class="tabs vertical">
<li id="tab-general" data-action="switch-tab" data-tab="general" class="active">
<a class="i18n_options_tab_general"></a>
<span class="icon"></span>
<ul id="nav-tablist" class="tabs vertical"
role="tablist" data-action="switch-tab"
data-keys="ArrowLeft ArrowUp ArrowRight ArrowDown">
<li id="tab-general" role="tab" data-tab="general"
aria-selected="true" aria-controls="content-general"
tabindex="0">
<span class="i18n_options_tab_general"></span>
</li>
<li id="tab-advanced" data-action="switch-tab" data-tab="advanced-allFilterLists">
<a class="i18n_options_tab_advanced"></a>
<span class="icon"></span>
<li id="tab-advanced" role="tab" data-tab="advanced"
data-subtab="advanced-allFilterLists"
aria-controls="content-advanced" tabindex="-1">
<span class="i18n_options_tab_advanced"></span>
</li>
<li id="tab-help" data-action="switch-tab" data-tab="help">
<a class="i18n_options_tab_help"></a>
<span class="icon"></span>
<li id="tab-help" role="tab" data-tab="help"
aria-controls="content-help" tabindex="-1">
<span class="i18n_options_tab_help"></span>
</li>
</ul>
</nav>
<a id="link-version">
<span class="i18n_options_version"></span>
<span id="abp-version"></span>
</a>
<footer>
<ul class="tabs vertical bottom">
<li id="tab-share">
<a class="i18n_options_tab_share"></a>
<span class="icon"></span>
<ul class="tabs vertical bottom" data-action="open-doclink"
data-keys="Enter">
<li id="tab-share" data-doclink="share-general" tabindex="0">
<span class="i18n_options_tab_share"></span>
</li>
<li id="tab-contribute">
<a class="i18n_options_tab_contribute"></a>
<span class="icon"></span>
<li id="tab-contribute" data-doclink="contribute" tabindex="0">
<span class="i18n_options_tab_contribute"></span>
</li>
</ul>
</footer>
......@@ -76,7 +82,7 @@
<div id="dialog-background"></div>
<!-- General tab content -->
<div id="content-general" class="tab-content">
<div id="content-general" role="tabpanel" aria-labelledby="tab-general">
<div>
<h1 class="i18n_options_blocking_title"></h1>
<div class="hbox">
......@@ -192,7 +198,8 @@
</div>
<!-- Advanced tab content -->
<div id="content-advanced" class="tab-content">
<div id="content-advanced" role="tabpanel"
aria-labelledby="tab-advanced">
<div>
<h1 class="i18n_options_tweaks_title"></h1>
<ul id="tweaks" class="table">
......@@ -230,12 +237,20 @@
<span class="i18n_options_readMore"
data-tooltip="options_filterList_title_tooltip"></span>
</h1>
<ul class="tabs horizontal">
<li class="i18n_options_tab_overview active" data-action="switch-tab" data-tab="advanced-allFilterLists"></li>
<li class="i18n_options_tab_ownList" data-action="switch-tab" data-tab="advanced-customFilters"></li>
<ul class="tabs horizontal" role="tablist" data-action="switch-tab"
data-keys="ArrowLeft ArrowUp ArrowRight ArrowDown">
<li id="tab-allFilterLists"
class="i18n_options_tab_overview active"
role="tab" data-tab="advanced-allFilterLists"
aria-selected="true" aria-controls="all-filter-lists"
tabindex="0"></li>
<li id="tab-customFilters" class="i18n_options_tab_ownList"
role="tab" data-tab="advanced-customFilters"
aria-controls="custom-filters" tabindex="-1"></li>
</ul>
<div id="filter-lists">
<div id="all-filter-lists">
<div id="all-filter-lists" role="tabpanel"
aria-labelledby="tab-allFilterLists">
<div class="table-header">
<h2 class="i18n_options_column_name"></h2>
<h2 class="i18n_options_column_date"></h2>
......@@ -281,7 +296,8 @@
</button>
</div>
</div>
<div id="custom-filters">
<div id="custom-filters" role="tabpanel"
aria-labelledby="tab-customFilters">
<h2 id="custom-filters-header">
<span class="i18n_options_customFilters_title"></span>
<span class="i18n_options_readMore"
......@@ -323,7 +339,7 @@
</div>
<!-- Help tab content -->
<div id="content-help" class="tab-content">
<div id="content-help" role="tabpanel" aria-labelledby="tab-help">
<h1 class="i18n_options_faq_title"></h1>
<p class="i18n_options_faq_description"></p>
<p>
......
......@@ -470,6 +470,22 @@
});
}
function openDocLink(id)
{
getDocLink(id, function(link)
{
if (id == "share-general")
openSharePopup(link);
else
location.href = link;
});
}
function switchTab(id)
{
location.hash = id;
}
function onClick(e)
{
var context = document.querySelector(".show-context-menu");
......@@ -488,6 +504,7 @@
element = element.parentElement;
}
var element = findParentData(e.target, "action", true);
var actions = element.getAttribute("data-action").split(",");
for (var i = 0; i < actions.length; i++)
{
......@@ -527,7 +544,12 @@
closeDialog();
break;
case "open-dialog":
openDialog(element.getAttribute("data-dialog"));
var dialog = findParentData(element, "dialog", false);
openDialog(dialog);
break;
case "open-doclink":
var doclink = findParentData(element, "doclink", false);
openDocLink(doclink);
break;
case "save-custom-filters":
sendMessageHandleErrors(
......@@ -542,8 +564,8 @@
});
break;
case "switch-tab":
document.body.setAttribute("data-tab",
element.getAttribute("data-tab"));
var tabId = findParentData(e.target, "tab", false);
switchTab(tabId);
break;
case "toggle-pref":
ext.backgroundPage.sendMessage(
......@@ -611,6 +633,122 @@
}
}
function getKey(e)
{
// e.keyCode has been deprecated so we attempt to use e.key
if ("key" in e)
return e.key;
return getKey.keys[e.keyCode];
}
getKey.keys = {
9: "Tab",
13: "Enter",
27: "Escape",
37: "ArrowLeft",
38: "ArrowUp",
39: "ArrowRight",
40: "ArrowDown"
};
function onKeyUp(e)
{
var key = getKey(e);
var element = document.activeElement;
if (!key || !element)
return;
var container = findParentData(element, "action", true);
if (!container || !container.hasAttribute("data-keys"))
return;
var keys = container.getAttribute("data-keys").split(" ");
if (keys.indexOf(key) < 0)
return;
switch (container.getAttribute("data-action"))
{
case "add-domain-exception":
addWhitelistedDomain();
break;
case "open-doclink":
var doclink = findParentData(element, "doclink", false);
openDocLink(doclink);
break;
case "switch-tab":
if (key == "Enter")
{
var tabId = findParentData(element, "tab", false);
switchTab(tabId);
}
else if (element.hasAttribute("aria-selected"))
{
if (key == "ArrowLeft" || key == "ArrowUp")
{
element = element.previousElementSibling
|| container.lastElementChild;
}
else if (key == "ArrowRight" || key == "ArrowDown")
{
element = element.nextElementSibling
|| container.firstElementChild;
}
var tabId = findParentData(element, "tab", false);
switchTab(tabId);
}
break;
}
}
function selectTabItem(tabId, container, focus)
{
// Show tab content
document.body.setAttribute("data-tab", tabId);
// Select tab
var tabList = container.querySelector("[role='tablist']");
if (!tabList)
return null;
var previousTab = tabList.querySelector("[aria-selected]");
previousTab.removeAttribute("aria-selected");
previousTab.setAttribute("tabindex", -1);
var tab = tabList.querySelector("li[data-tab='" + tabId + "']");
tab.setAttribute("aria-selected", true);
tab.setAttribute("tabindex", 0);
var tabContentId = tab.getAttribute("aria-controls");
var tabContent = document.getElementById(tabContentId);
// Select sub tabs
if (tab.hasAttribute("data-subtab"))
selectTabItem(tab.getAttribute("data-subtab"), tabContent, false);
if (tab && focus)
tab.focus();
return tabContent;
}
function onHashChange()
{
var hash = location.hash.substr(1);
if (!hash)
return;
// Select tab and parent tabs
var tabIds = hash.split("-");
var tabContent = document.body;
for (var i = 0; i < tabIds.length; i++)
{
var tabId = tabIds.slice(0, i + 1).join("-");
tabContent = selectTabItem(tabId, tabContent, true);
if (!tabContent)
break;
}
}
function onDOMLoaded()
{
populateLists();
......@@ -623,19 +761,6 @@
searchStyle.innerHTML = "#all-lang-table li:not([data-search*=\"" + this.value.toLowerCase() + "\"]) { display: none; }";
}
function getKey(e)
{
// e.keyCode has been deprecated so we attempt to use e.key
if ("key" in e)
return e.key;
return getKey.keys[e.keyCode];
}
getKey.keys = {
9: "Tab",
13: "Enter",
27: "Escape"
};
// Initialize navigation sidebar
ext.backgroundPage.sendMessage(
{
......@@ -651,16 +776,12 @@
E("link-version").setAttribute("href", link);
});
getDocLink("contribute", function(link)
{
document.querySelector("#tab-contribute a").setAttribute("href", link);
});
updateShareLink();
updateTooltips();
// Initialize interactive UI elements
document.body.addEventListener("click", onClick, false);
document.body.addEventListener("keyup", onKeyUp, false);
var placeholderValue = getMessage("options_dialog_language_find");
E("find-language").setAttribute("placeholder", placeholderValue);
E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
......@@ -748,6 +869,8 @@
break;
}
}, false);
onHashChange();
}
var focusedBeforeDialog = null;
......@@ -1005,13 +1128,6 @@
checkbox.setAttribute("aria-checked", value);
}
function onShareLinkClick(e)
{
e.preventDefault();
getDocLink("share-general", openSharePopup);
}
function updateShareLink()
{
var shareResources = [
......@@ -1028,14 +1144,7 @@
if (!--checksRemaining)
{
// Hide the share tab if a script on the share page would be blocked
var tab = E("tab-share");
if (isAnyBlocked)
{
tab.hidden = true;
tab.removeEventListener("click", onShareLinkClick, false);
}
else
tab.addEventListener("click", onShareLinkClick, false);
E("tab-share").hidden = isAnyBlocked;
}
}
......@@ -1177,4 +1286,5 @@
});
window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
window.addEventListener("hashchange", onHashChange, false);
})();
......@@ -198,39 +198,43 @@ button[role="checkbox"][aria-checked="true"]
.tabs.vertical li
{
height: 46px;
margin-top: -1px;
-moz-margin-end: -1px;
-webkit-margin-end: -1px;
-moz-margin-start: -1px;
-webkit-margin-start: -1px;
border-color: #CDCDCD transparent;
border-style: solid;
border-width: 1px;
font-size: 16px;
font-weight: 300;
line-height: 1em;
margin-top: -1px;
padding: 14px 20px;
}
body[data-tab|="general"] #tab-general,
body[data-tab|="advanced"] #tab-advanced,
body[data-tab|="help"] #tab-help
.tabs.vertical li a,
.tabs.vertical li span,
.tabs.vertical li::after
{
margin: auto 20px;
}
.tabs li[role="tab"]:focus
{
outline: none;
text-shadow: 0px 0px 1px #888;
}
.tabs li[role="tab"][aria-selected]
{
background-color: #FFFFFF;
border-radius: 3px 0px 0px 3px;
border-width: 1px;
font-weight: 600;
-moz-border-start-color: #CDCDCD;
-webkit-border-start-color: #CDCDCD;
-moz-margin-end: -1px;
-webkit-margin-end: -1px;
-moz-margin-start: -1px;
-webkit-margin-start: -1px;
-moz-padding-end: 21px;
-webkit-padding-end: 21px;
-moz-padding-start: 21px;
-webkit-padding-start: 21px;
font-weight: 600;
background-color: #FFF;
}
html[dir="rtl"] body[data-tab|="general"] #tab-general,
html[dir="rtl"] body[data-tab|="advanced"] #tab-advanced,
html[dir="rtl"] body[data-tab|="help"] #tab-help
html[dir="rtl"] .tabs li[role="tab"][aria-selected]
{
border-radius: 0px 3px 3px 0px;
}
......@@ -251,33 +255,40 @@ html[dir="rtl"] body[data-tab|="help"] #tab-help
border-bottom: none;
}
#nav-sidebar ul li .icon
#nav-sidebar ul li span
{
width: 100%;
}
#nav-sidebar ul li::after
{
content: "";
min-width: 14px;
height: 14px;
width: 14px;
background-image: url(options-sprite.png);
}
#tab-general .icon
#tab-general::after
{
background-position: -16px -18px;
}
#tab-advanced .icon
#tab-advanced::after
{
background-position: -46px -18px;
}
#tab-help .icon
#tab-help::after
{
background-position: -1px -18px;
}
#tab-share .icon
#tab-share::after
{
background-position: -61px -18px;
}
#tab-contribute .icon
#tab-contribute::after
{
background-position: -31px -18px;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment