[Pkg-mozext-commits] [adblock-plus] 08/87: Issue 2408 - Improved accessibility of checkboxes in options page

David Prévot taffit at moszumanska.debian.org
Sat Apr 30 17:59:02 UTC 2016


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository adblock-plus.

commit 9faeb60aa7cf712a4dc848476498cc100f83d0fd
Author: Thomas Greiner <thomas at adblockplus.org>
Date:   Wed Jan 27 15:53:02 2016 +0100

    Issue 2408 - Improved accessibility of checkboxes in options page
---
 options.html     |  20 ++++++-----
 options.js       | 108 ++++++++++++++++++++++++++++++++++++++++---------------
 skin/options.css |  25 +++++++++++--
 3 files changed, 112 insertions(+), 41 deletions(-)

diff --git a/options.html b/options.html
index dde0b64..a5e8695 100644
--- a/options.html
+++ b/options.html
@@ -71,12 +71,12 @@
         </footer>
       </div>
     </div>
-    <div id="tab-content">
+    <div id="content">
       <div id="content-wrapper">
         <div id="dialog-background"></div>
 
         <!-- General tab content -->
-        <div id="content-general">
+        <div id="content-general" class="tab-content">
           <div>
             <h1 class="i18n_options_blocking_title"></h1>
             <div class="hbox">
@@ -97,7 +97,7 @@
                 </div>
                 <ul id="blocking-languages-table" class="table list">
                   <template>
-                    <input type="checkbox" class="control" />
+                    <button role="checkbox" class="control"></button>
                     <span class="display"></span>
                   </template>
                 </ul>
@@ -122,14 +122,14 @@
                 <div id="custom-wrapper">
                   <ul id="recommend-list-table" class="table list">
                     <template>
-                      <input type="checkbox" class="control" />
+                      <button role="checkbox" class="control"></button>
                       <span class="display"></span>
                       <span class="popular"></span>
                     </template>
                   </ul>
                   <ul id="custom-list-table" class="table list">
                     <template>
-                      <input type="checkbox" class="control" />
+                      <button role="checkbox" class="control"></button>
                       <span class="display"></span>
                     </template>
                   </ul>
@@ -161,7 +161,7 @@
                 </div>
                 <ul id="acceptableads-table" class="table list">
                   <template>
-                    <input type="checkbox" class="control" />
+                    <button role="checkbox" class="control"></button>
                     <span class="display"></span>
                   </template>
                 </ul>
@@ -211,12 +211,14 @@
         </div>
 
         <!-- Advanced tab content -->
-        <div id="content-advanced">
+        <div id="content-advanced" class="tab-content">
           <div>
             <h1><span class="i18n_options_tweaks_title"></span><a class="i18n_options_readMore tooltip" href="#"></a></h1>
             <ul class="table" style="width: auto;">
               <li>
-                <input type="checkbox" id="easylist"/><span id="block-element-explanation" class="i18n_options_tweaks_blockElement"></span></li>
+                <button role="checkbox" id="easylist"></button>
+                <span id="block-element-explanation" class="i18n_options_tweaks_blockElement"></span>
+              </li>
             </ul>
           </div>
           <div>
@@ -281,7 +283,7 @@
         </div>
 
         <!-- Help tab content -->
-        <div id="content-help">
+        <div id="content-help" class="tab-content">
           <h1 class="i18n_options_faq_title"></h1>
           <p class="i18n_options_faq_description"></p>
           <p>
diff --git a/options.js b/options.js
index f9ec572..300c724 100644
--- a/options.js
+++ b/options.js
@@ -23,6 +23,7 @@
   var recommendationsMap = Object.create(null);
   var filtersMap = Object.create(null);
   var collections = Object.create(null);
+  var maxLabelId = 0;
 
   function Collection(details)
   {
@@ -64,19 +65,19 @@
       for (var i = 0; i < arguments.length; i++) 
       {
         var item = arguments[i];
-        var text = item.title || item.url || item.text;
         var listItem = document.createElement("li");
         listItem.appendChild(document.importNode(template.content, true));
         listItem.setAttribute("data-access", item.url || item.text);
-        listItem.querySelector(".display").textContent = text;
-        if (text)
-          listItem.setAttribute("data-search", text.toLowerCase());
 
+        var labelId = "label-" + (++maxLabelId);
+        listItem.querySelector(".display").setAttribute("id", labelId);
         var control = listItem.querySelector(".control");
         if (control)
         {
+          // We use aria-labelledby to avoid triggering the control when
+          // interacting with the label
+          control.setAttribute("aria-labelledby", labelId);
           control.addEventListener("click", this.details[j].onClick, false);
-          control.checked = item.disabled == false;
         }
 
         this._setEmpty(table, null);
@@ -84,6 +85,7 @@
           table.insertBefore(listItem, table.childNodes[this.items.indexOf(item)]);
         else
           table.appendChild(listItem);
+        this.updateItem(item);
       }
     }
     return length;
@@ -100,12 +102,53 @@
     {
       var table = E(this.details[i].id);
       var element = table.childNodes[index];
+
+      // Element gets removed so make sure to handle focus appropriately
+      var control = element.querySelector(".control");
+      if (control && control == document.activeElement)
+      {
+        if (!focusNextElement(element.parentElement, control))
+        {
+          // Fall back to next focusable element within same tab or dialog
+          var focusableElement = element.parentElement;
+          while (focusableElement)
+          {
+            if (focusableElement.classList.contains("tab-content")
+                || focusableElement.classList.contains("dialog-content"))
+              break;
+
+            focusableElement = focusableElement.parentElement;
+          }
+          focusNextElement(focusableElement || document, control);
+        }
+      }
+
       element.parentElement.removeChild(element);
       if (this.items.length == 0)
         this._setEmpty(table, this.details[i].emptyText);
     }
   };
 
+  Collection.prototype.updateItem = function(item)
+  {
+    var access = (item.url || item.text).replace(/'/g, "\\'");
+    for (var i = 0; i < this.details.length; i++)
+    {
+      var table = E(this.details[i].id);
+      var element = table.querySelector("[data-access='" + access + "']");
+      if (!element)
+        continue;
+
+      var text = item.title || item.url || item.text;
+      element.querySelector(".display").textContent = text;
+      if (text)
+        element.setAttribute("data-search", text.toLowerCase());
+      var control = element.querySelector(".control[role='checkbox']");
+      if (control)
+        control.setAttribute("aria-checked", item.disabled == false);
+    }
+  };
+
   Collection.prototype.clearAll = function()
   {
     this.items = [];
@@ -119,11 +162,27 @@
     }
   };
 
+  function focusNextElement(container, currentElement)
+  {
+    var focusables = container.querySelectorAll("a, button, input, .control");
+    focusables = Array.prototype.slice.call(focusables);
+    var index = focusables.indexOf(currentElement);
+    index += (index == focusables.length - 1) ? -1 : 1;
+
+    var nextElement = focusables[index];
+    if (!nextElement)
+      return false;
+
+    nextElement.focus();
+    return true;
+  }
+
   function onToggleSubscriptionClick(e)
   {
     e.preventDefault();
-    var subscriptionUrl = e.target.parentNode.getAttribute("data-access");
-    if (!e.target.checked)
+    var checkbox = e.target;
+    var subscriptionUrl = checkbox.parentElement.getAttribute("data-access");
+    if (checkbox.getAttribute("aria-checked") == "true")
     {
       ext.backgroundPage.sendMessage({
         type: "subscriptions.remove",
@@ -220,30 +279,21 @@
       {
         function onObjectChanged()
         {
-          var access = (subscriptionUrl || subscription.text).replace(/'/g, "\\'");
-          var elements = document.querySelectorAll("[data-access='" + access + "']");
-          for (var i = 0; i < elements.length; i++)
+          for (var i in collections)
+            collections[i].updateItem(subscription);
+
+          var recommendation = recommendationsMap[subscriptionUrl];
+          if (recommendation && recommendation.type == "ads")
           {
-            var element = elements[i];
-            var control = element.querySelector(".control");
-            if (control.localName == "input")
-              control.checked = subscription.disabled == false;
-            if (subscriptionUrl in recommendationsMap)
+            if (subscription.disabled == false)
             {
-              var recommendation = recommendationsMap[subscriptionUrl];
-              if (recommendation.type == "ads")
-              {
-                if (subscription.disabled == false)
-                {
-                  collections.allLangs.removeItem(subscription);
-                  collections.langs.addItems(subscription);
-                }
-                else
-                {
-                  collections.allLangs.addItems(subscription);
-                  collections.langs.removeItem(subscription);
-                }
-              }
+              collections.allLangs.removeItem(subscription);
+              collections.langs.addItems(subscription);
+            }
+            else
+            {
+              collections.allLangs.addItems(subscription);
+              collections.langs.removeItem(subscription);
             }
           }
         }
diff --git a/skin/options.css b/skin/options.css
index e322cd6..2f43e15 100644
--- a/skin/options.css
+++ b/skin/options.css
@@ -92,6 +92,25 @@ input[type="text"], input[type="search"]
   box-sizing: border-box;
 }
 
+button[role="checkbox"]
+{
+  vertical-align: top;
+  width: 18px;
+  height: 18px;
+  margin-top: 0px;
+  -moz-margin-end: 20px;
+  -webkit-margin-end: 20px;
+  padding: 0px;
+  border: none;
+  background-color: transparent;
+  background-position: -51px 0px;
+}
+
+button[role="checkbox"][aria-checked="true"]
+{
+  background-position: -68px 0px;
+}
+
 .option-name
 {
   display: flex;
@@ -269,7 +288,7 @@ html[dir="rtl"] body[data-tab="help"] #tab-help
   border-top: none;
 }
 
-#tab-content
+#content
 {
   background-color: #FFFFFF;
   border: 1px solid #CDCDCD;
@@ -279,7 +298,7 @@ html[dir="rtl"] body[data-tab="help"] #tab-help
   padding: 0px 60px 40px 60px;
 }
 
-#tab-content h1
+#content h1
 {
   border-bottom: 1px solid #CDCDCD;
   margin: 0px;
@@ -474,7 +493,7 @@ div.button
   padding-bottom: 10px;
 }
 
-.icon, .table input[type="checkbox"]::before, .table button.delete,
+.icon, .table button[role="checkbox"], .table button.delete,
 #content-help a::before, #dialog-close::before,
 #custom-filters-add button::after,
 #dialog-body button::before

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/adblock-plus.git



More information about the Pkg-mozext-commits mailing list