summaryrefslogtreecommitdiffstats
path: root/extensions/BugModal/web
diff options
context:
space:
mode:
authorDavid Lawrence <dkl@mozilla.com>2017-02-21 22:56:56 +0100
committerDavid Lawrence <dkl@mozilla.com>2017-02-21 22:56:56 +0100
commit318b9027db03bc7397fa8072811db33783d29976 (patch)
tree2cd3b8dd9848a4678402f473433e5e817ad4b2e0 /extensions/BugModal/web
parentbbd5ffb01a1f9feb277dd33e8b4333840fb26949 (diff)
downloadbugzilla-318b9027db03bc7397fa8072811db33783d29976.tar.gz
bugzilla-318b9027db03bc7397fa8072811db33783d29976.tar.xz
Bug 1280363 - [a11y] Make the Actions menu button accessible for keyboard and screen readers
Diffstat (limited to 'extensions/BugModal/web')
-rw-r--r--extensions/BugModal/web/bug_modal.js101
-rw-r--r--extensions/BugModal/web/comments.js43
-rw-r--r--extensions/BugModal/web/dropdown.css52
-rw-r--r--extensions/BugModal/web/dropdown.js98
4 files changed, 171 insertions, 123 deletions
diff --git a/extensions/BugModal/web/bug_modal.js b/extensions/BugModal/web/bug_modal.js
index 894745016..f65c12be3 100644
--- a/extensions/BugModal/web/bug_modal.js
+++ b/extensions/BugModal/web/bug_modal.js
@@ -377,13 +377,7 @@ $(function() {
}
});
- // action button menu
-
- $.contextMenu({
- selector: '#action-menu-btn',
- trigger: 'left',
- items: $.contextMenu.fromMenu($('#action-menu'))
- });
+ // action button actions
// reset
$('#action-reset')
@@ -1006,99 +1000,6 @@ $(function() {
BUGZILLA.remaining_time = $('#remaining_time').val();
});
- // new bug button
- $.contextMenu({
- selector: '#new-bug-btn',
- trigger: 'left',
- items: [
- {
- name: 'Create a new Bug',
- callback: function() {
- window.open('enter_bug.cgi', '_blank');
- }
- },
- {
- name: '\u2026 in this product',
- callback: function() {
- window.open('enter_bug.cgi?product=' + encodeURIComponent($('#product').val()), '_blank');
- }
- },
- {
- name: '\u2026 in this component',
- callback: function() {
- window.open('enter_bug.cgi?' +
- 'product=' + encodeURIComponent($('#product').val()) +
- '&component=' + encodeURIComponent($('#component').val()), '_blank');
- }
- },
- {
- name: '\u2026 that blocks this bug',
- callback: function() {
- window.open('enter_bug.cgi?format=__default__' +
- '&product=' + encodeURIComponent($('#product').val()) +
- '&blocked=' + BUGZILLA.bug_id, '_blank');
- }
- },
- {
- name: '\u2026 that depends on this bug',
- callback: function() {
- window.open('enter_bug.cgi?format=__default__' +
- '&product=' + encodeURIComponent($('#product').val()) +
- '&dependson=' + BUGZILLA.bug_id, '_blank');
- }
- },
- {
- name: '\u2026 as a clone of this bug',
- callback: function() {
- window.open('enter_bug.cgi?format=__default__' +
- '&product=' + encodeURIComponent($('#product').val()) +
- '&cloned_bug_id=' + BUGZILLA.bug_id, '_blank');
- }
- },
- {
- name: '\u2026 as a clone, in a different product',
- callback: function() {
- window.open('enter_bug.cgi?format=__default__' +
- '&cloned_bug_id=' + BUGZILLA.bug_id, '_blank');
- }
- },
- ]
- });
-
- var format_items = [
- {
- name: 'For Printing',
- callback: function() {
- window.location.href = 'show_bug.cgi?format=multiple&id=' + BUGZILLA.bug_id;
- }
- },
- {
- name: 'XML',
- callback: function() {
- window.location.href = 'show_bug.cgi?ctype=xml&id=' + BUGZILLA.bug_id;
- }
- },
- {
- name: 'Legacy',
- callback: function() {
- window.location.href = 'show_bug.cgi?format=default&id=' + BUGZILLA.bug_id;
- }
- }
- ];
- if (!BUGZILLA.bug_secure) {
- format_items.push({
- name: 'JSON',
- callback: function() {
- window.location.href = 'rest/bug/' + BUGZILLA.bug_id;
- }
- });
- }
- $.contextMenu({
- selector: '#format-btn',
- trigger: 'left',
- items: format_items
- });
-
// "reset to default" checkboxes
$('#product, #component')
.change(function(event) {
diff --git a/extensions/BugModal/web/comments.js b/extensions/BugModal/web/comments.js
index 7eb933cfc..04894506e 100644
--- a/extensions/BugModal/web/comments.js
+++ b/extensions/BugModal/web/comments.js
@@ -189,12 +189,6 @@ $(function() {
}
});
- $.contextMenu({
- selector: '#view-menu-btn',
- trigger: 'left',
- items: $.contextMenu.fromMenu($('#view-menu'))
- });
-
function updateTagsMenu() {
var tags = [];
$('.comment-tags').each(function() {
@@ -218,21 +212,24 @@ $(function() {
}
btn.show();
- var menuItems = [
- { name: 'Reset', tag: '' },
- "--"
- ];
+ // clear out old li items. Always leave the first one (Reset)
+ var $li = $('#comment-tags-menu li');
+ for (var i = 1, l = $li.length; i < l; i++) {
+ $li.eq(i).remove();
+ }
+
+ // add new li items
$.each(tagNames, function(key, value) {
- menuItems.push({ name: value + ' (' + tags[value] + ')', tag: value });
+ $('#comment-tags-menu')
+ .append($('<li role="presentation">')
+ .append($('<a role="menuitem" tabindex="-1" data-comment-tag="' + value + '">')
+ .append(value + ' (' + tags[value] + ')')));
});
- $.contextMenu('destroy', '#comment-tags-btn');
- $.contextMenu({
- selector: '#comment-tags-btn',
- trigger: 'left',
- items: menuItems,
- callback: function(key, opt) {
- var tag = opt.commands[key].tag;
+ $('a[data-comment-tag]').each(function() {
+ $(this).click(function() {
+ var $that = $(this);
+ var tag = $that.data('comment-tag');
if (tag === '') {
$('.change-spinner:visible').each(function() {
toggleChange($(this), 'reset');
@@ -241,17 +238,17 @@ $(function() {
}
var firstComment = false;
$('.change-spinner:visible').each(function() {
- var that = $(this);
- var commentTags = tagsFromDom(that.parents('.comment').find('.comment-tags'));
+ var $that = $(this);
+ var commentTags = tagsFromDom($that.parents('.comment').find('.comment-tags'));
var hasTag = $.inArrayIn(tag, commentTags) >= 0;
- toggleChange(that, hasTag ? 'show' : 'hide');
+ toggleChange($that, hasTag ? 'show' : 'hide');
if (hasTag && !firstComment) {
- firstComment = that;
+ firstComment = $that;
}
});
if (firstComment)
$.scrollTo(firstComment);
- }
+ });
});
}
diff --git a/extensions/BugModal/web/dropdown.css b/extensions/BugModal/web/dropdown.css
new file mode 100644
index 000000000..977a7a57f
--- /dev/null
+++ b/extensions/BugModal/web/dropdown.css
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This Source Code Form is "Incompatible With Secondary Licenses", as
+ * defined by the Mozilla Public License, v. 2.0. */
+
+/* The container <div> - needed to position the dropdown content */
+.dropdown {
+ position: relative;
+ display: inline-block;
+}
+
+/* Dropdown Content (Hidden by Default) */
+.dropdown-content {
+ position: absolute;
+ background-color: #eee;
+ min-width: 120px;
+ z-index: 1;
+ text-align: left;
+ margin: 0;
+ padding: 0;
+ border: 1px solid #ddd;
+ -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
+ box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
+ list-style: none;
+}
+
+.dropdown-content.menu-up {
+ bottom: 100%;
+}
+
+.dropdown-separator {
+ border-bottom: 1px solid #ddd;
+}
+
+/* Links inside the dropdown */
+.dropdown-content a {
+ white-space: nowrap;
+ background-color: #eee;
+ color: black !important;
+ padding: 4px 8px;
+ text-decoration: none !important;
+ display: block;
+}
+
+/* Change color of dropdown links on hover */
+.dropdown-content li .active {
+ text-decoration: none;
+ background-color: #39f;
+}
diff --git a/extensions/BugModal/web/dropdown.js b/extensions/BugModal/web/dropdown.js
new file mode 100644
index 000000000..3198c09b1
--- /dev/null
+++ b/extensions/BugModal/web/dropdown.js
@@ -0,0 +1,98 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This Source Code Form is "Incompatible With Secondary Licenses", as
+ * defined by the Mozilla Public License, v. 2.0. */
+
+$(function() {
+ 'use strict';
+
+ $(window).click(function(e) {
+ // clicking dropdown button opens or closes the dropdown content
+ if (!$(e.target).hasClass('dropdown-button')) {
+ $('.dropdown-button').each(function() {
+ toggleDropDown(e, $(this), $('#' + $(this).attr('aria-controls')), 1);
+ });
+ }
+ }).keydown(function(e) {
+ // Escape key hides the dropdown if visible
+ if (e.keyCode == 27) {
+ $('.dropdown-button').each(function() {
+ var $button = $(this);
+ if ($button.siblings('.dropdown-content').is(':visible')) {
+ toggleDropDown(e, $button, $('#' + $button.attr('aria-controls')), 1);
+ $button.focus();
+ }
+ });
+ }
+ // allow arrow up and down keys to choose one of the dropdown items if menu visible
+ if (e.keyCode == 38 || e.keyCode == 40) {
+ $('.dropdown-content').each(function() {
+ var $content = $(this);
+ if ($content.is(':visible')) {
+ e.preventDefault();
+ e.stopPropagation();
+ var $li = $content.find('li');
+ // if none focused select the first or last
+ var $any_focused = $content.find('a:focus');
+ if ($any_focused.length == 0) {
+ var index = e.keyCode == 40 ? 0 : $li.length - 1;
+ var $link = $li.eq(index).find('a');
+ $link.addClass('active').focus();
+ return;
+ }
+ // otherwise move up or down the list based on arrow key pressed
+ var inc = e.keyCode == 40 ? 1 : -1;
+ var move = $content.find('a:focus').parent('li').index() + inc;
+ var $link = $li.eq(move % $li.length).find('a');
+ $content.find('a').removeClass('active');
+ $link.addClass('active').focus();
+ }
+ });
+ }
+
+ // enter clicks on a link
+ if (e.keyCode == 13) {
+ $('.dropdown-content:visible a.active').trigger('click');
+ }
+ });
+
+ $('.dropdown-content a').hover(
+ function(){ $(this).addClass('active') },
+ function(){ $(this).removeClass('active') }
+ );
+
+ $('.dropdown').each(function() {
+ var $div = $(this);
+ var $button = $div.find('.dropdown-button');
+ var $content = $div.find('.dropdown-content');
+ $button.click(function(e) {
+ toggleDropDown(e, $button, $content);
+ }).keydown(function(e) {
+ // allow enter to toggle menu
+ if (e.keyCode == 13) {
+ toggleDropDown(e, $button, $content);
+ }
+ });
+ });
+
+ function toggleDropDown(e, $button, $content, hide_only) {
+ // If clicking a real link we do not want to prevent default behavior
+ if (!$(e.target).is('.dropdown-content a') || $(e.target).is('.dropbown-button')) {
+ e.preventDefault();
+ }
+ e.stopPropagation();
+ // clear all active links
+ $content.find('a').removeClass('active');
+ if ($content.is(':visible')) {
+ $content.hide();
+ $button.attr('aria-expanded', false);
+ }
+ // if not using Escape or clicking outside the dropdown div, then we are hiding
+ else if (!hide_only) {
+ $content.show();
+ $button.attr('aria-expanded', true);
+ }
+ }
+});