Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: new-options.js

Issue 29348642: Issue 2409 - Improved accessibility of tabs in options page (Closed)
Left Patch Set: Created July 25, 2016, 3:01 p.m.
Right Patch Set: Created July 26, 2016, 12:48 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « new-options.html ('k') | skin/new-options.css » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 case "edit-domain-exception": 537 case "edit-domain-exception":
538 document.querySelector("#whitelisting .controls").classList.add("mode- edit"); 538 document.querySelector("#whitelisting .controls").classList.add("mode- edit");
539 E("whitelisting-textbox").focus(); 539 E("whitelisting-textbox").focus();
540 break; 540 break;
541 case "import-subscription": 541 case "import-subscription":
542 var url = E("blockingList-textbox").value; 542 var url = E("blockingList-textbox").value;
543 addEnableSubscription(url); 543 addEnableSubscription(url);
544 closeDialog(); 544 closeDialog();
545 break; 545 break;
546 case "open-dialog": 546 case "open-dialog":
547 var dialog = findParentData(element, "dialog", false); 547 var dialog = findParentData(element, "dialog", false);
saroyanm 2016/07/25 17:13:34 Are you assigning element to the variable because
Thomas Greiner 2016/07/26 12:50:49 Yes, that makes it easier to read than for instanc
548 openDialog(dialog); 548 openDialog(dialog);
549 break; 549 break;
550 case "open-doclink": 550 case "open-doclink":
551 var doclink = findParentData(element, "doclink", false); 551 var doclink = findParentData(element, "doclink", false);
552 openDocLink(doclink); 552 openDocLink(doclink);
553 break; 553 break;
554 case "save-custom-filters": 554 case "save-custom-filters":
555 sendMessageHandleErrors( 555 sendMessageHandleErrors(
556 { 556 {
557 type: "filters.importRaw", 557 type: "filters.importRaw",
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 27: "Escape", 646 27: "Escape",
647 37: "ArrowLeft", 647 37: "ArrowLeft",
648 38: "ArrowUp", 648 38: "ArrowUp",
649 39: "ArrowRight", 649 39: "ArrowRight",
650 40: "ArrowDown" 650 40: "ArrowDown"
651 }; 651 };
652 652
653 function onKeyUp(e) 653 function onKeyUp(e)
654 { 654 {
655 var key = getKey(e); 655 var key = getKey(e);
656 var element = document.querySelector(":focus"); 656 var element = document.activeElement;
saroyanm 2016/07/25 17:13:34 We probably should be able to use document.activeE
Thomas Greiner 2016/07/26 12:50:49 You're absolutely right! Done.
657 if (!key || !element) 657 if (!key || !element)
658 return; 658 return;
659 659
660 var container = findParentData(element, "action", true); 660 var container = findParentData(element, "action", true);
661 if (!container || !container.hasAttribute("data-keys")) 661 if (!container || !container.hasAttribute("data-keys"))
662 return; 662 return;
663 663
664 var keys = container.getAttribute("data-keys").split(" "); 664 var keys = container.getAttribute("data-keys").split(" ");
665 if (keys.indexOf(key) < 0) 665 if (keys.indexOf(key) < 0)
666 return; 666 return;
667 667
668 switch (container.getAttribute("data-action")) 668 switch (container.getAttribute("data-action"))
669 { 669 {
670 case "add-domain-exception": 670 case "add-domain-exception":
671 addWhitelistedDomain(); 671 addWhitelistedDomain();
672 break; 672 break;
673 case "open-doclink": 673 case "open-doclink":
674 var doclink = findParentData(element, "doclink", false); 674 var doclink = findParentData(element, "doclink", false);
675 openDocLink(doclink); 675 openDocLink(doclink);
676 break; 676 break;
677 case "switch-tab": 677 case "switch-tab":
678 if (key == "Enter") 678 if (key == "Enter")
679 { 679 {
680 var tabId = findParentData(element, "tab", false); 680 var tabId = findParentData(element, "tab", false);
saroyanm 2016/07/25 17:13:34 If I don't miss something this can go outside of i
Thomas Greiner 2016/07/26 12:50:49 `switchTab()` is only called if either Enter is pr
681 switchTab(tabId); 681 switchTab(tabId);
682 } 682 }
683 else if (element.hasAttribute("aria-selected")) 683 else if (element.hasAttribute("aria-selected"))
684 { 684 {
685 if (key == "ArrowLeft" || key == "ArrowUp") 685 if (key == "ArrowLeft" || key == "ArrowUp")
686 { 686 {
687 element = element.previousElementSibling 687 element = element.previousElementSibling
688 || container.lastElementChild; 688 || container.lastElementChild;
689 } 689 }
690 else if (key == "ArrowRight" || key == "ArrowDown") 690 else if (key == "ArrowRight" || key == "ArrowDown")
691 { 691 {
692 element = element.nextElementSibling 692 element = element.nextElementSibling
693 || container.firstElementChild; 693 || container.firstElementChild;
694 } 694 }
695 695
696 var tabId = findParentData(element, "tab", false); 696 var tabId = findParentData(element, "tab", false);
697 switchTab(tabId); 697 switchTab(tabId);
698 } 698 }
699 break; 699 break;
700 } 700 }
701 } 701 }
702 702
703 function selectTabItem(tabId, container, focus)
704 {
705 // Show tab content
706 document.body.setAttribute("data-tab", tabId);
707
708 // Select tab
709 var tabList = container.querySelector("[role='tablist']");
710 if (!tabList)
711 return null;
712
713 var previousTab = tabList.querySelector("[aria-selected]");
714 previousTab.removeAttribute("aria-selected");
715 previousTab.setAttribute("tabindex", -1);
716
717 var tab = tabList.querySelector("li[data-tab='" + tabId + "']");
718 tab.setAttribute("aria-selected", true);
719 tab.setAttribute("tabindex", 0);
720
721 var tabContentId = tab.getAttribute("aria-controls");
722 var tabContent = document.getElementById(tabContentId);
723
724 // Select sub tabs
725 if (tab.hasAttribute("data-subtab"))
726 selectTabItem(tab.getAttribute("data-subtab"), tabContent, false);
727
728 if (tab && focus)
729 tab.focus();
730
731 return tabContent;
732 }
733
703 function onHashChange() 734 function onHashChange()
704 { 735 {
705 var hash = location.hash.substr(1); 736 var hash = location.hash.substr(1);
706 if (!hash) 737 if (!hash)
707 return; 738 return;
708
709 function selectTab(tabId, container, focus)
saroyanm 2016/07/25 17:13:34 This nested function will always recreated on each
Thomas Greiner 2016/07/26 12:50:50 Done. I wanted to avoid that this function is use
710 {
711 // Show tab content
712 document.body.setAttribute("data-tab", tabId);
713
714 // Select tab
715 var tabList = container.querySelector("[role='tablist']");
716 if (!tabList)
717 return null;
718
719 var previousTab = tabList.querySelector("[aria-selected]");
720 previousTab.removeAttribute("aria-selected");
721 previousTab.setAttribute("tabindex", -1);
722
723 var tab = tabList.querySelector("li[data-tab='" + tabId + "']");
724 tab.setAttribute("aria-selected", true);
725 tab.setAttribute("tabindex", 0);
726
727 var tabContentId = tab.getAttribute("aria-controls");
728 var tabContent = document.getElementById(tabContentId);
729
730 // Select sub tabs
731 if (tab.hasAttribute("data-subtab"))
732 selectTab(tab.getAttribute("data-subtab"), tabContent, false);
733
734 if (tab && focus)
735 tab.focus();
736
737 return tabContent;
738 }
739 739
740 // Select tab and parent tabs 740 // Select tab and parent tabs
741 var tabIds = hash.split("-"); 741 var tabIds = hash.split("-");
742 var tabContent = document.body; 742 var tabContent = document.body;
743 for (var i = 0; i < tabIds.length; i++) 743 for (var i = 0; i < tabIds.length; i++)
744 { 744 {
745 var tabId = tabIds.slice(0, i + 1).join("-"); 745 var tabId = tabIds.slice(0, i + 1).join("-");
746 tabContent = selectTab(tabId, tabContent, true); 746 tabContent = selectTabItem(tabId, tabContent, true);
747 if (!tabContent) 747 if (!tabContent)
748 break; 748 break;
749 } 749 }
750 } 750 }
751 751
752 function onDOMLoaded() 752 function onDOMLoaded()
753 { 753 {
754 populateLists(); 754 populateLists();
755 function onFindLanguageKeyUp() 755 function onFindLanguageKeyUp()
756 { 756 {
(...skipping 17 matching lines...) Expand all
774 getDocLink("releases", function(link) 774 getDocLink("releases", function(link)
775 { 775 {
776 E("link-version").setAttribute("href", link); 776 E("link-version").setAttribute("href", link);
777 }); 777 });
778 778
779 updateShareLink(); 779 updateShareLink();
780 updateTooltips(); 780 updateTooltips();
781 781
782 // Initialize interactive UI elements 782 // Initialize interactive UI elements
783 document.body.addEventListener("click", onClick, false); 783 document.body.addEventListener("click", onClick, false);
784 document.body.addEventListener("keyup", onKeyUp, false);
784 var placeholderValue = getMessage("options_dialog_language_find"); 785 var placeholderValue = getMessage("options_dialog_language_find");
785 E("find-language").setAttribute("placeholder", placeholderValue); 786 E("find-language").setAttribute("placeholder", placeholderValue);
786 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false); 787 E("find-language").addEventListener("keyup", onFindLanguageKeyUp, false);
787 E("whitelisting-textbox").addEventListener("keypress", function(e) 788 E("whitelisting-textbox").addEventListener("keypress", function(e)
788 { 789 {
789 if (getKey(e) == "Enter") 790 if (getKey(e) == "Enter")
790 addWhitelistedDomain(); 791 addWhitelistedDomain();
791 }, false); 792 }, false);
792 793
793 // Advanced tab 794 // Advanced tab
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 } 863 }
863 else if (e.target.classList.contains("focus-last")) 864 else if (e.target.classList.contains("focus-last"))
864 { 865 {
865 e.preventDefault(); 866 e.preventDefault();
866 this.querySelector(".focus-first").focus(); 867 this.querySelector(".focus-first").focus();
867 } 868 }
868 break; 869 break;
869 } 870 }
870 }, false); 871 }, false);
871 872
872 document.body.addEventListener("keyup", onKeyUp, true);
saroyanm 2016/07/25 17:13:34 Detail: I think this listener can be defined with
Thomas Greiner 2016/07/26 12:50:49 It's out of place here, I agree. I moved it to the
873 onHashChange(); 873 onHashChange();
874 } 874 }
875 875
876 var focusedBeforeDialog = null; 876 var focusedBeforeDialog = null;
877 function openDialog(name) 877 function openDialog(name)
878 { 878 {
879 var dialog = E("dialog"); 879 var dialog = E("dialog");
880 dialog.setAttribute("aria-hidden", false); 880 dialog.setAttribute("aria-hidden", false);
881 dialog.setAttribute("aria-labelledby", "dialog-title-" + name); 881 dialog.setAttribute("aria-labelledby", "dialog-title-" + name);
882 document.body.setAttribute("data-dialog", name); 882 document.body.setAttribute("data-dialog", name);
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 ext.backgroundPage.sendMessage( 1281 ext.backgroundPage.sendMessage(
1282 { 1282 {
1283 type: "subscriptions.listen", 1283 type: "subscriptions.listen",
1284 filter: ["added", "disabled", "homepage", "lastDownload", "removed", 1284 filter: ["added", "disabled", "homepage", "lastDownload", "removed",
1285 "title", "downloadStatus", "downloading"] 1285 "title", "downloadStatus", "downloading"]
1286 }); 1286 });
1287 1287
1288 window.addEventListener("DOMContentLoaded", onDOMLoaded, false); 1288 window.addEventListener("DOMContentLoaded", onDOMLoaded, false);
1289 window.addEventListener("hashchange", onHashChange, false); 1289 window.addEventListener("hashchange", onHashChange, false);
1290 })(); 1290 })();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld