Skip to content

Commit 6e6f23b

Browse files
authored
Restore Accessibility for Dropdown (#16576)
* Restore #10096/#8638 and re-fix #15172 This PR restores the vendored and patched dropdow from #8638. It however, abandons the calls to `click()` using instead the default dropdown click calls instead. This prevents the issue of the dropdown grabbing focus permanently however, this may have negative effects on the effect of focus on the dropdowns. Of note, the behaviour of the template selector dropdown on the repo creation page is slightly odd - I don't believe that this odd behaviour is caused by this PR but rather by the feed source for this. I suspect that the dropdown should be adding a delete button to its selection. Fix #15172 References: #7057 Signed-off-by: Andrew Thornton <art27@cantab.net> * leverage fomantic-build instead Signed-off-by: Andrew Thornton <art27@cantab.net> * as per jookia Signed-off-by: Andrew Thornton <art27@cantab.net>
1 parent fd39e6d commit 6e6f23b

File tree

5 files changed

+4450
-10
lines changed

5 files changed

+4450
-10
lines changed

.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ root: true
22
reportUnusedDisableDirectives: true
33

44
ignorePatterns:
5+
- /web_src/js/vendor
56
- /templates/base/head.tmpl
67
- /templates/repo/activity.tmpl
78
- /templates/repo/view_file.tmpl

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ fomantic:
699699
cd $(FOMANTIC_WORK_DIR) && npm install --no-save
700700
cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
701701
cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
702+
cp -f web_src/js/vendor/dropdown.js $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/definitions/modules
702703
cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
703704

704705
.PHONY: webpack

web_src/fomantic/build/semantic.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -30873,7 +30873,7 @@ ol.ui.suffixed.list li:before,
3087330873
List
3087430874
---------------*/
3087530875

30876-
/* Menu divider shouldn't apply */
30876+
/* Menu divider shouldnt apply */
3087730877

3087830878
.ui.menu .list .item:before {
3087930879
background: none !important;
@@ -31802,7 +31802,7 @@ Floated Menu / Item
3180231802
opacity: 1;
3180331803
}
3180431804

31805-
/* Icon Glyph */
31805+
/* Icon Gylph */
3180631806

3180731807
.ui.icon.menu i.icon:before {
3180831808
opacity: 1;

web_src/fomantic/build/semantic.js

+108-8
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ $.api = $.fn.api = function(parameters) {
142142
response = JSON.parse(response);
143143
}
144144
catch(e) {
145-
// isn't json string
145+
// isnt json string
146146
}
147147
}
148148
return response;
@@ -2220,7 +2220,7 @@ $.fn.dimmer = function(parameters) {
22202220

22212221
event: {
22222222
click: function(event) {
2223-
module.verbose('Determining if event occurred on dimmer', event);
2223+
module.verbose('Determining if event occured on dimmer', event);
22242224
if( $dimmer.find(event.target).length === 0 || $(event.target).is(selector.content) ) {
22252225
module.hide();
22262226
event.stopImmediatePropagation();
@@ -2827,6 +2827,13 @@ $.fn.dimmer.settings = {
28272827
*
28282828
*/
28292829

2830+
/*
2831+
* Copyright 2019 The Gitea Authors
2832+
* Released under the MIT license
2833+
* http://opensource.org/licenses/MIT
2834+
* This version has been modified by Gitea to improve accessibility.
2835+
*/
2836+
28302837
;(function ($, window, document, undefined) {
28312838

28322839
'use strict';
@@ -2860,6 +2867,7 @@ $.fn.dropdown = function(parameters) {
28602867
query = arguments[0],
28612868
methodInvoked = (typeof query == 'string'),
28622869
queryArguments = [].slice.call(arguments, 1),
2870+
lastAriaID = 1,
28632871
returnedValue
28642872
;
28652873

@@ -2952,6 +2960,8 @@ $.fn.dropdown = function(parameters) {
29522960

29532961
module.observeChanges();
29542962
module.instantiate();
2963+
2964+
module.aria.setup();
29552965
}
29562966

29572967
},
@@ -3152,6 +3162,86 @@ $.fn.dropdown = function(parameters) {
31523162
}
31533163
},
31543164

3165+
aria: {
3166+
setup: function() {
3167+
var role = module.aria.guessRole();
3168+
if( role !== 'menu' ) {
3169+
return;
3170+
}
3171+
$module.attr('aria-busy', 'true');
3172+
$module.attr('role', 'menu');
3173+
$module.attr('aria-haspopup', 'menu');
3174+
$module.attr('aria-expanded', 'false');
3175+
$menu.find('.divider').attr('role', 'separator');
3176+
$item.attr('role', 'menuitem');
3177+
$item.each(function (index, item) {
3178+
if( !item.id ) {
3179+
item.id = module.aria.nextID('menuitem');
3180+
}
3181+
});
3182+
$text = $module
3183+
.find('> .text')
3184+
.eq(0)
3185+
;
3186+
if( $module.data('content') ) {
3187+
$text.attr('aria-hidden');
3188+
$module.attr('aria-label', $module.data('content'));
3189+
}
3190+
else {
3191+
$text.attr('id', module.aria.nextID('menutext'));
3192+
$module.attr('aria-labelledby', $text.attr('id'));
3193+
}
3194+
$module.attr('aria-busy', 'false');
3195+
},
3196+
nextID: function(prefix) {
3197+
var nextID;
3198+
do {
3199+
nextID = prefix + '_' + lastAriaID++;
3200+
} while( document.getElementById(nextID) );
3201+
return nextID;
3202+
},
3203+
setExpanded: function(expanded) {
3204+
if( $module.attr('aria-haspopup') ) {
3205+
$module.attr('aria-expanded', expanded);
3206+
}
3207+
},
3208+
refreshDescendant: function() {
3209+
if( $module.attr('aria-haspopup') !== 'menu' ) {
3210+
return;
3211+
}
3212+
var
3213+
$currentlySelected = $item.not(selector.unselectable).filter('.' + className.selected).eq(0),
3214+
$activeItem = $menu.children('.' + className.active).eq(0),
3215+
$selectedItem = ($currentlySelected.length > 0)
3216+
? $currentlySelected
3217+
: $activeItem
3218+
;
3219+
if( $selectedItem ) {
3220+
$module.attr('aria-activedescendant', $selectedItem.attr('id'));
3221+
}
3222+
else {
3223+
module.aria.removeDescendant();
3224+
}
3225+
},
3226+
removeDescendant: function() {
3227+
if( $module.attr('aria-haspopup') == 'menu' ) {
3228+
$module.removeAttr('aria-activedescendant');
3229+
}
3230+
},
3231+
guessRole: function() {
3232+
var
3233+
isIcon = $module.hasClass('icon'),
3234+
hasSearch = module.has.search(),
3235+
hasInput = ($input.length > 0),
3236+
isMultiple = module.is.multiple()
3237+
;
3238+
if ( !isIcon && !hasSearch && !hasInput && !isMultiple ) {
3239+
return 'menu';
3240+
}
3241+
return 'unknown';
3242+
}
3243+
},
3244+
31553245
setup: {
31563246
api: function() {
31573247
var
@@ -3198,6 +3288,7 @@ $.fn.dropdown = function(parameters) {
31983288
if(settings.allowTab) {
31993289
module.set.tabbable();
32003290
}
3291+
$item.attr('tabindex', '-1');
32013292
},
32023293
select: function() {
32033294
var
@@ -3344,6 +3435,8 @@ $.fn.dropdown = function(parameters) {
33443435
return true;
33453436
}
33463437
if(settings.onShow.call(element) !== false) {
3438+
module.aria.setExpanded(true);
3439+
module.aria.refreshDescendant();
33473440
module.animate.show(function() {
33483441
if( module.can.click() ) {
33493442
module.bind.intent();
@@ -3366,9 +3459,11 @@ $.fn.dropdown = function(parameters) {
33663459
if( module.is.active() && !module.is.animatingOutward() ) {
33673460
module.debug('Hiding dropdown');
33683461
if(settings.onHide.call(element) !== false) {
3462+
module.aria.setExpanded(false);
3463+
module.aria.removeDescendant();
33693464
module.animate.hide(function() {
33703465
module.remove.visible();
3371-
// hiding search focus
3466+
// hidding search focus
33723467
if ( module.is.focusedOnSearch() && preventBlur !== true ) {
33733468
$search.blur();
33743469
}
@@ -4319,7 +4414,7 @@ $.fn.dropdown = function(parameters) {
43194414
// allow selection with menu closed
43204415
if(isAdditionWithoutMenu) {
43214416
module.verbose('Selecting item from keyboard shortcut', $selectedItem);
4322-
module.event.item.click.call($selectedItem, event);
4417+
$selectedItem[0].click();
43234418
if(module.is.searchSelection()) {
43244419
module.remove.searchTerm();
43254420
}
@@ -4339,7 +4434,7 @@ $.fn.dropdown = function(parameters) {
43394434
}
43404435
else if(selectedIsSelectable) {
43414436
module.verbose('Selecting item from keyboard shortcut', $selectedItem);
4342-
module.event.item.click.call($selectedItem, event);
4437+
$selectedItem[0].click();
43434438
if(module.is.searchSelection()) {
43444439
module.remove.searchTerm();
43454440
if(module.is.multiple()) {
@@ -4367,6 +4462,7 @@ $.fn.dropdown = function(parameters) {
43674462
.closest(selector.item)
43684463
.addClass(className.selected)
43694464
;
4465+
module.aria.refreshDescendant();
43704466
event.preventDefault();
43714467
}
43724468
}
@@ -4383,6 +4479,7 @@ $.fn.dropdown = function(parameters) {
43834479
.find(selector.item).eq(0)
43844480
.addClass(className.selected)
43854481
;
4482+
module.aria.refreshDescendant();
43864483
event.preventDefault();
43874484
}
43884485
}
@@ -4407,6 +4504,7 @@ $.fn.dropdown = function(parameters) {
44074504
$nextItem
44084505
.addClass(className.selected)
44094506
;
4507+
module.aria.refreshDescendant();
44104508
module.set.scrollPosition($nextItem);
44114509
if(settings.selectOnKeydown && module.is.single()) {
44124510
module.set.selectedItem($nextItem);
@@ -4434,6 +4532,7 @@ $.fn.dropdown = function(parameters) {
44344532
$nextItem
44354533
.addClass(className.selected)
44364534
;
4535+
module.aria.refreshDescendant();
44374536
module.set.scrollPosition($nextItem);
44384537
if(settings.selectOnKeydown && module.is.single()) {
44394538
module.set.selectedItem($nextItem);
@@ -5403,6 +5502,7 @@ $.fn.dropdown = function(parameters) {
54035502
module.set.scrollPosition($nextValue);
54045503
$selectedItem.removeClass(className.selected);
54055504
$nextValue.addClass(className.selected);
5505+
module.aria.refreshDescendant();
54065506
if(settings.selectOnKeydown && module.is.single()) {
54075507
module.set.selectedItem($nextValue);
54085508
}
@@ -11937,7 +12037,7 @@ $.fn.progress = function(parameters) {
1193712037
*
1193812038
* @param min A minimum value within multiple values
1193912039
* @param total A total amount of multiple values
11940-
* @returns {number} A precision. Could be 1, 10, 100, ... 1e+10.
12040+
* @returns {number} A precison. Could be 1, 10, 100, ... 1e+10.
1194112041
*/
1194212042
derivePrecision: function(min, total) {
1194312043
var precisionPower = 0
@@ -12837,7 +12937,7 @@ $.fn.progress.settings = {
1283712937
nonNumeric : 'Progress value is non numeric',
1283812938
tooHigh : 'Value specified is above 100%',
1283912939
tooLow : 'Value specified is below 0%',
12840-
sumExceedsTotal : 'Sum of multiple values exceed total',
12940+
sumExceedsTotal : 'Sum of multple values exceed total',
1284112941
},
1284212942

1284312943
regExp: {
@@ -18076,7 +18176,7 @@ $.fn.transition.settings = {
1807618176

1807718177
// possible errors
1807818178
error: {
18079-
noAnimation : 'Element is no longer attached to DOM. Unable to animate. Use silent setting to suppress this warning in production.',
18179+
noAnimation : 'Element is no longer attached to DOM. Unable to animate. Use silent setting to surpress this warning in production.',
1808018180
repeated : 'That animation is already occurring, cancelling repeated animation',
1808118181
method : 'The method you called is not defined',
1808218182
support : 'This browser does not support CSS animations'

0 commit comments

Comments
 (0)