MDL-71672 javascript: Fix the issue of focusOnShowSelector being ignored

When focusOnShowSelector is not present, as a fallback, focus the first
focusable element in YUI dialogues
Ref:
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role
This commit is contained in:
Shamim Rezaie 2021-06-02 17:59:04 +10:00
parent 8453fe0ddb
commit 2092f152b2
4 changed files with 62 additions and 44 deletions

View file

@ -43,7 +43,12 @@ var DIALOGUE_NAME = 'Moodle dialogue',
MENUBAR_SELECTOR = '[role=menubar]', MENUBAR_SELECTOR = '[role=menubar]',
DOT = '.', DOT = '.',
HAS_ZINDEX = 'moodle-has-zindex', HAS_ZINDEX = 'moodle-has-zindex',
CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]', CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]):not([disabled]):not([tabindex^="-"]),' +
'a[href]:not([disabled]):not([tabindex^="-"]),' +
'button:not([disabled]):not([tabindex^="-"]),' +
'textarea:not([disabled]):not([tabindex^="-"]),' +
'select:not([disabled]):not([tabindex^="-"]),' +
'[tabindex]:not([disabled]):not([tabindex^="-"])',
FORM_SELECTOR = 'form'; FORM_SELECTOR = 'form';
/** /**
@ -316,10 +321,6 @@ Y.extend(DIALOGUE, Y.Panel, {
Y.one(titlebar).setStyle('cursor', 'move'); Y.one(titlebar).setStyle('cursor', 'move');
} }
} }
require(['core/local/aria/focuslock'], function(FocusLockManager) {
// Trap focus to the current bounding box.
FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode());
}.bind(this));
// Only do accessibility hiding for modals because the ARIA spec // Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal. // says that all ARIA dialogues should be modal.
@ -410,9 +411,12 @@ Y.extend(DIALOGUE, Y.Panel, {
Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth'); Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth');
}, },
_focus: function() {
this.focus();
},
show: function() { show: function() {
var result = null, var result = null,
header = this.headerNode,
content = this.bodyNode, content = this.bodyNode,
focusSelector = this.get('focusOnShowSelector'), focusSelector = this.get('focusOnShowSelector'),
focusNode = null; focusNode = null;
@ -429,16 +433,18 @@ Y.extend(DIALOGUE, Y.Panel, {
focusNode = this.get('boundingBox').one(focusSelector); focusNode = this.get('boundingBox').one(focusSelector);
} }
if (!focusNode) { if (!focusNode) {
// Fall back to the header or the content if no focus node was found yet. // Fall back to the first focusable element in the body of the dialogue if no focus node was found yet.
if (header && header !== '') { if (content && content !== '') {
focusNode = header; focusNode = content.one(CAN_RECEIVE_FOCUS_SELECTOR);
} else if (content && content !== '') {
focusNode = content;
} }
} }
if (focusNode) { require(['core/local/aria/focuslock'], function(FocusLockManager) {
focusNode.focus(); // Trap focus to the current bounding box.
} FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode());
if (focusNode) {
focusNode.focus();
}
}.bind(this));
return result; return result;
}, },

File diff suppressed because one or more lines are too long

View file

@ -43,7 +43,12 @@ var DIALOGUE_NAME = 'Moodle dialogue',
MENUBAR_SELECTOR = '[role=menubar]', MENUBAR_SELECTOR = '[role=menubar]',
DOT = '.', DOT = '.',
HAS_ZINDEX = 'moodle-has-zindex', HAS_ZINDEX = 'moodle-has-zindex',
CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]', CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]):not([disabled]):not([tabindex^="-"]),' +
'a[href]:not([disabled]):not([tabindex^="-"]),' +
'button:not([disabled]):not([tabindex^="-"]),' +
'textarea:not([disabled]):not([tabindex^="-"]),' +
'select:not([disabled]):not([tabindex^="-"]),' +
'[tabindex]:not([disabled]):not([tabindex^="-"])',
FORM_SELECTOR = 'form'; FORM_SELECTOR = 'form';
/** /**
@ -316,10 +321,6 @@ Y.extend(DIALOGUE, Y.Panel, {
Y.one(titlebar).setStyle('cursor', 'move'); Y.one(titlebar).setStyle('cursor', 'move');
} }
} }
require(['core/local/aria/focuslock'], function(FocusLockManager) {
// Trap focus to the current bounding box.
FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode());
}.bind(this));
// Only do accessibility hiding for modals because the ARIA spec // Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal. // says that all ARIA dialogues should be modal.
@ -410,9 +411,12 @@ Y.extend(DIALOGUE, Y.Panel, {
Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth'); Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth');
}, },
_focus: function() {
this.focus();
},
show: function() { show: function() {
var result = null, var result = null,
header = this.headerNode,
content = this.bodyNode, content = this.bodyNode,
focusSelector = this.get('focusOnShowSelector'), focusSelector = this.get('focusOnShowSelector'),
focusNode = null; focusNode = null;
@ -429,16 +433,18 @@ Y.extend(DIALOGUE, Y.Panel, {
focusNode = this.get('boundingBox').one(focusSelector); focusNode = this.get('boundingBox').one(focusSelector);
} }
if (!focusNode) { if (!focusNode) {
// Fall back to the header or the content if no focus node was found yet. // Fall back to the first focusable element in the body of the dialogue if no focus node was found yet.
if (header && header !== '') { if (content && content !== '') {
focusNode = header; focusNode = content.one(CAN_RECEIVE_FOCUS_SELECTOR);
} else if (content && content !== '') {
focusNode = content;
} }
} }
if (focusNode) { require(['core/local/aria/focuslock'], function(FocusLockManager) {
focusNode.focus(); // Trap focus to the current bounding box.
} FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode());
if (focusNode) {
focusNode.focus();
}
}.bind(this));
return result; return result;
}, },

View file

@ -13,7 +13,12 @@ var DIALOGUE_NAME = 'Moodle dialogue',
MENUBAR_SELECTOR = '[role=menubar]', MENUBAR_SELECTOR = '[role=menubar]',
DOT = '.', DOT = '.',
HAS_ZINDEX = 'moodle-has-zindex', HAS_ZINDEX = 'moodle-has-zindex',
CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]), a[href], button, textarea, select, [tabindex]', CAN_RECEIVE_FOCUS_SELECTOR = 'input:not([type="hidden"]):not([disabled]):not([tabindex^="-"]),' +
'a[href]:not([disabled]):not([tabindex^="-"]),' +
'button:not([disabled]):not([tabindex^="-"]),' +
'textarea:not([disabled]):not([tabindex^="-"]),' +
'select:not([disabled]):not([tabindex^="-"]),' +
'[tabindex]:not([disabled]):not([tabindex^="-"])',
FORM_SELECTOR = 'form'; FORM_SELECTOR = 'form';
/** /**
@ -286,10 +291,6 @@ Y.extend(DIALOGUE, Y.Panel, {
Y.one(titlebar).setStyle('cursor', 'move'); Y.one(titlebar).setStyle('cursor', 'move');
} }
} }
require(['core/local/aria/focuslock'], function(FocusLockManager) {
// Trap focus to the current bounding box.
FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode());
}.bind(this));
// Only do accessibility hiding for modals because the ARIA spec // Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal. // says that all ARIA dialogues should be modal.
@ -380,9 +381,12 @@ Y.extend(DIALOGUE, Y.Panel, {
Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth'); Math.floor(Y.one(document.body).get('winWidth')) < this.get('responsiveWidth');
}, },
_focus: function() {
this.focus();
},
show: function() { show: function() {
var result = null, var result = null,
header = this.headerNode,
content = this.bodyNode, content = this.bodyNode,
focusSelector = this.get('focusOnShowSelector'), focusSelector = this.get('focusOnShowSelector'),
focusNode = null; focusNode = null;
@ -399,16 +403,18 @@ Y.extend(DIALOGUE, Y.Panel, {
focusNode = this.get('boundingBox').one(focusSelector); focusNode = this.get('boundingBox').one(focusSelector);
} }
if (!focusNode) { if (!focusNode) {
// Fall back to the header or the content if no focus node was found yet. // Fall back to the first focusable element in the body of the dialogue if no focus node was found yet.
if (header && header !== '') { if (content && content !== '') {
focusNode = header; focusNode = content.one(CAN_RECEIVE_FOCUS_SELECTOR);
} else if (content && content !== '') {
focusNode = content;
} }
} }
if (focusNode) { require(['core/local/aria/focuslock'], function(FocusLockManager) {
focusNode.focus(); // Trap focus to the current bounding box.
} FocusLockManager.trapFocus(this.get('boundingBox').getDOMNode());
if (focusNode) {
focusNode.focus();
}
}.bind(this));
return result; return result;
}, },