Skip to content

Instantly share code, notes, and snippets.

@zeripath
Created July 29, 2021 21:13
Show Gist options
  • Save zeripath/30ee2e474df94ac837541652032b3c5f to your computer and use it in GitHub Desktop.
Save zeripath/30ee2e474df94ac837541652032b3c5f to your computer and use it in GitHub Desktop.
foomantic accessibility patch - working copy from #8638
--- web_src/fomantic/build/components/dropdown.js 1985-10-26 09:15:00.000000000 +0100
+++ web_src/js/vendor/dropdown.js 2021-07-29 21:53:25.769541139 +0100
@@ -8,6 +8,13 @@
*
*/
+/*
+ * Copyright 2019 The Gitea Authors
+ * Released under the MIT license
+ * http://opensource.org/licenses/MIT
+ * This version has been modified by Gitea to improve accessibility.
+ */
+
;(function ($, window, document, undefined) {
'use strict';
@@ -41,6 +48,7 @@
query = arguments[0],
methodInvoked = (typeof query == 'string'),
queryArguments = [].slice.call(arguments, 1),
+ lastAriaID = 1,
returnedValue
;
@@ -133,6 +141,8 @@
module.observeChanges();
module.instantiate();
+
+ module.aria.setup();
}
},
@@ -333,6 +343,86 @@
}
},
+ aria: {
+ setup: function() {
+ var role = module.aria.guessRole();
+ if( role !== 'menu' ) {
+ return;
+ }
+ $module.attr('aria-busy', 'true');
+ $module.attr('role', 'menu');
+ $module.attr('aria-haspopup', 'menu');
+ $module.attr('aria-expanded', 'false');
+ $menu.find('.divider').attr('role', 'separator');
+ $item.attr('role', 'menuitem');
+ $item.each(function (index, item) {
+ if( !item.id ) {
+ item.id = module.aria.nextID('menuitem');
+ }
+ });
+ $text = $module
+ .find('> .text')
+ .eq(0)
+ ;
+ if( $module.data('content') ) {
+ $text.attr('aria-hidden');
+ $module.attr('aria-label', $module.data('content'));
+ }
+ else {
+ $text.attr('id', module.aria.nextID('menutext'));
+ $module.attr('aria-labelledby', $text.attr('id'));
+ }
+ $module.attr('aria-busy', 'false');
+ },
+ nextID: function(prefix) {
+ var nextID;
+ do {
+ nextID = prefix + '_' + lastAriaID++;
+ } while( document.getElementById(nextID) );
+ return nextID;
+ },
+ setExpanded: function(expanded) {
+ if( $module.attr('aria-haspopup') ) {
+ $module.attr('aria-expanded', expanded);
+ }
+ },
+ refreshDescendant: function() {
+ if( $module.attr('aria-haspopup') !== 'menu' ) {
+ return;
+ }
+ var
+ $currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
+ $activeItem = $menu.children('.' + className.active).eq(0),
+ $selectedItem = ($currentlySelected.length > 0)
+ ? $currentlySelected
+ : $activeItem
+ ;
+ if( $selectedItem ) {
+ $module.attr('aria-activedescendant', $selectedItem.attr('id'));
+ }
+ else {
+ module.aria.removeDescendant();
+ }
+ },
+ removeDescendant: function() {
+ if( $module.attr('aria-haspopup') == 'menu' ) {
+ $module.removeAttr('aria-activedescendant');
+ }
+ },
+ guessRole: function() {
+ var
+ isIcon = $module.hasClass('icon'),
+ hasSearch = module.has.search(),
+ hasInput = ($input.length > 0),
+ isMultiple = module.is.multiple()
+ ;
+ if ( !isIcon && !hasSearch && !hasInput && !isMultiple ) {
+ return 'menu';
+ }
+ return 'unknown';
+ }
+ },
+
setup: {
api: function() {
var
@@ -379,6 +469,7 @@
if(settings.allowTab) {
module.set.tabbable();
}
+ $item.attr('tabindex', '-1');
},
select: function() {
var
@@ -525,6 +616,8 @@
return true;
}
if(settings.onShow.call(element) !== false) {
+ module.aria.setExpanded(true);
+ module.aria.refreshDescendant();
module.animate.show(function() {
if( module.can.click() ) {
module.bind.intent();
@@ -547,6 +640,8 @@
if( module.is.active() && !module.is.animatingOutward() ) {
module.debug('Hiding dropdown');
if(settings.onHide.call(element) !== false) {
+ module.aria.setExpanded(false);
+ module.aria.removeDescendant();
module.animate.hide(function() {
module.remove.visible();
// hidding search focus
@@ -995,7 +1090,7 @@
;
if(settings.allowAdditions || (hasSelected && !module.is.multiple())) {
module.debug('Forcing partial selection to selected item', $selectedItem);
- module.event.item.click.call($selectedItem, {}, true);
+ $selectedItem[0].click();
}
else {
module.remove.searchTerm();
@@ -1500,7 +1595,7 @@
// allow selection with menu closed
if(isAdditionWithoutMenu) {
module.verbose('Selecting item from keyboard shortcut', $selectedItem);
- module.event.item.click.call($selectedItem, event);
+ $selectedItem[0].click();
if(module.is.searchSelection()) {
module.remove.searchTerm();
}
@@ -1520,7 +1615,7 @@
}
else if(selectedIsSelectable) {
module.verbose('Selecting item from keyboard shortcut', $selectedItem);
- module.event.item.click.call($selectedItem, event);
+ $selectedItem[0].click();
if(module.is.searchSelection()) {
module.remove.searchTerm();
if(module.is.multiple()) {
@@ -1548,6 +1643,7 @@
.closest(selector.item)
.addClass(className.selected)
;
+ module.aria.refreshDescendant();
event.preventDefault();
}
}
@@ -1564,6 +1660,7 @@
.find(selector.item).eq(0)
.addClass(className.selected)
;
+ module.aria.refreshDescendant();
event.preventDefault();
}
}
@@ -1588,6 +1685,7 @@
$nextItem
.addClass(className.selected)
;
+ module.aria.refreshDescendant();
module.set.scrollPosition($nextItem);
if(settings.selectOnKeydown && module.is.single()) {
module.set.selectedItem($nextItem);
@@ -1615,6 +1713,7 @@
$nextItem
.addClass(className.selected)
;
+ module.aria.refreshDescendant();
module.set.scrollPosition($nextItem);
if(settings.selectOnKeydown && module.is.single()) {
module.set.selectedItem($nextItem);
@@ -2584,6 +2683,7 @@
module.set.scrollPosition($nextValue);
$selectedItem.removeClass(className.selected);
$nextValue.addClass(className.selected);
+ module.aria.refreshDescendant();
if(settings.selectOnKeydown && module.is.single()) {
module.set.selectedItem($nextValue);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment