MDL-51799 javascript: dialogue accessibility

Moved setting the aria visiblity of the dialogues from the show
and hide functions into the visibility change handler to stop
multiple calls.

Also made the visibility checker just continue to buffer the elements
it hides, rather than clearning them, on multiple calls.
This commit is contained in:
Ryan Wyllie
2015-10-29 05:41:59 +00:00
parent 53378d63e2
commit c07b265f77
4 changed files with 92 additions and 53 deletions
@@ -108,6 +108,16 @@ Y.extend(DIALOGUE, Y.Panel, {
*/
_originalPosition: null,
/**
* The list of elements that have been aria hidden when displaying
* this dialogue.
*
* @property _hiddenSiblings
* @protected
* @type Array
*/
_hiddenSiblings: null,
/**
* Initialise the dialogue.
*
@@ -116,6 +126,9 @@ Y.extend(DIALOGUE, Y.Panel, {
initializer : function() {
var bb;
// Initialise the element cache.
this._hiddenSiblings = [];
if (this.get('render')) {
this.render();
}
@@ -242,6 +255,7 @@ Y.extend(DIALOGUE, Y.Panel, {
var titlebar, bb;
if (e.attrName === 'visible') {
this.get('maskNode').addClass(CSS.LIGHTBOX);
// Going from visible to hidden.
if (e.prevVal && !e.newVal) {
bb = this.get('boundingBox');
if (this._resizeevent) {
@@ -253,7 +267,13 @@ Y.extend(DIALOGUE, Y.Panel, {
this._orientationevent = null;
}
bb.detach('key', this.keyDelegation);
if (this.get('modal')) {
// Hide this dialogue from screen readers.
this.setAccessibilityHidden();
}
}
// Going from hidden to visible.
if (!e.prevVal && e.newVal) {
// This needs to be done each time the dialog is shown as new dialogs may have been opened.
this.applyZIndex();
@@ -267,6 +287,13 @@ Y.extend(DIALOGUE, Y.Panel, {
}
}
this.keyDelegation();
// Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal.
if (this.get('modal')) {
// Make this dialogue visible to screen readers.
this.setAccessibilityVisible();
}
}
if (this.get('center') && !e.prevVal && e.newVal) {
this.centerDialogue();
@@ -366,13 +393,6 @@ Y.extend(DIALOGUE, Y.Panel, {
this.lockScroll.enableScrollLock(this.shouldResizeFullscreen());
}
// Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal.
if (this.get('modal')) {
// Make this dialogue visible to screen readers.
this.setAccessibilityVisible();
}
// Try and find a node to focus on using the focusOnShowSelector attribute.
if (focusSelector !== null) {
focusNode = this.get('boundingBox').one(focusSelector);
@@ -400,11 +420,6 @@ Y.extend(DIALOGUE, Y.Panel, {
}
}
if (this.get('modal')) {
// Hide this dialogue from screen readers.
this.setAccessibilityHidden();
}
// Unlock scroll if the plugin is present.
if (this.lockScroll) {
this.lockScroll.disableScrollLock();
@@ -462,8 +477,6 @@ Y.extend(DIALOGUE, Y.Panel, {
// Get the element that contains this dialogue because we need it
// to filter out from the document.body child elements.
var container = this.get(BASE);
// Keep a record of any elements we change so that they can be reverted later.
this.hiddenSiblings = [];
// We need to get a list containing each sibling element and the shallowest
// non-ancestral nodes in the DOM. We can shortcut this a little by leveraging
@@ -478,7 +491,7 @@ Y.extend(DIALOGUE, Y.Panel, {
if (hidden !== 'true') {
// Save their current state.
node.setData('previous-aria-hidden', hidden);
this.hiddenSiblings.push(node);
this._hiddenSiblings.push(node);
// Hide this node from screen readers.
node.set('aria-hidden', 'true');
@@ -502,7 +515,7 @@ Y.extend(DIALOGUE, Y.Panel, {
container.set('aria-hidden', 'true');
// Restore the sibling nodes back to their original values.
Y.Array.each(this.hiddenSiblings, function(node) {
Y.Array.each(this._hiddenSiblings, function(node) {
var previousValue = node.getData('previous-aria-hidden');
// If the element didn't previously have an aria-hidden attribute
// then we can just remove the one we set.
@@ -515,7 +528,7 @@ Y.extend(DIALOGUE, Y.Panel, {
});
// Clear the cache. No longer need to store these.
this.hiddenSiblings = [];
this._hiddenSiblings = [];
}
}, {
NAME : DIALOGUE_NAME,
File diff suppressed because one or more lines are too long
@@ -108,6 +108,16 @@ Y.extend(DIALOGUE, Y.Panel, {
*/
_originalPosition: null,
/**
* The list of elements that have been aria hidden when displaying
* this dialogue.
*
* @property _hiddenSiblings
* @protected
* @type Array
*/
_hiddenSiblings: null,
/**
* Initialise the dialogue.
*
@@ -116,6 +126,9 @@ Y.extend(DIALOGUE, Y.Panel, {
initializer : function() {
var bb;
// Initialise the element cache.
this._hiddenSiblings = [];
if (this.get('render')) {
this.render();
}
@@ -242,6 +255,7 @@ Y.extend(DIALOGUE, Y.Panel, {
var titlebar, bb;
if (e.attrName === 'visible') {
this.get('maskNode').addClass(CSS.LIGHTBOX);
// Going from visible to hidden.
if (e.prevVal && !e.newVal) {
bb = this.get('boundingBox');
if (this._resizeevent) {
@@ -253,7 +267,13 @@ Y.extend(DIALOGUE, Y.Panel, {
this._orientationevent = null;
}
bb.detach('key', this.keyDelegation);
if (this.get('modal')) {
// Hide this dialogue from screen readers.
this.setAccessibilityHidden();
}
}
// Going from hidden to visible.
if (!e.prevVal && e.newVal) {
// This needs to be done each time the dialog is shown as new dialogs may have been opened.
this.applyZIndex();
@@ -267,6 +287,13 @@ Y.extend(DIALOGUE, Y.Panel, {
}
}
this.keyDelegation();
// Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal.
if (this.get('modal')) {
// Make this dialogue visible to screen readers.
this.setAccessibilityVisible();
}
}
if (this.get('center') && !e.prevVal && e.newVal) {
this.centerDialogue();
@@ -366,13 +393,6 @@ Y.extend(DIALOGUE, Y.Panel, {
this.lockScroll.enableScrollLock(this.shouldResizeFullscreen());
}
// Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal.
if (this.get('modal')) {
// Make this dialogue visible to screen readers.
this.setAccessibilityVisible();
}
// Try and find a node to focus on using the focusOnShowSelector attribute.
if (focusSelector !== null) {
focusNode = this.get('boundingBox').one(focusSelector);
@@ -400,11 +420,6 @@ Y.extend(DIALOGUE, Y.Panel, {
}
}
if (this.get('modal')) {
// Hide this dialogue from screen readers.
this.setAccessibilityHidden();
}
// Unlock scroll if the plugin is present.
if (this.lockScroll) {
this.lockScroll.disableScrollLock();
@@ -462,8 +477,6 @@ Y.extend(DIALOGUE, Y.Panel, {
// Get the element that contains this dialogue because we need it
// to filter out from the document.body child elements.
var container = this.get(BASE);
// Keep a record of any elements we change so that they can be reverted later.
this.hiddenSiblings = [];
// We need to get a list containing each sibling element and the shallowest
// non-ancestral nodes in the DOM. We can shortcut this a little by leveraging
@@ -478,7 +491,7 @@ Y.extend(DIALOGUE, Y.Panel, {
if (hidden !== 'true') {
// Save their current state.
node.setData('previous-aria-hidden', hidden);
this.hiddenSiblings.push(node);
this._hiddenSiblings.push(node);
// Hide this node from screen readers.
node.set('aria-hidden', 'true');
@@ -502,7 +515,7 @@ Y.extend(DIALOGUE, Y.Panel, {
container.set('aria-hidden', 'true');
// Restore the sibling nodes back to their original values.
Y.Array.each(this.hiddenSiblings, function(node) {
Y.Array.each(this._hiddenSiblings, function(node) {
var previousValue = node.getData('previous-aria-hidden');
// If the element didn't previously have an aria-hidden attribute
// then we can just remove the one we set.
@@ -515,7 +528,7 @@ Y.extend(DIALOGUE, Y.Panel, {
});
// Clear the cache. No longer need to store these.
this.hiddenSiblings = [];
this._hiddenSiblings = [];
}
}, {
NAME : DIALOGUE_NAME,
+30 -17
View File
@@ -79,6 +79,16 @@ Y.extend(DIALOGUE, Y.Panel, {
*/
_originalPosition: null,
/**
* The list of elements that have been aria hidden when displaying
* this dialogue.
*
* @property _hiddenSiblings
* @protected
* @type Array
*/
_hiddenSiblings: null,
/**
* Initialise the dialogue.
*
@@ -87,6 +97,9 @@ Y.extend(DIALOGUE, Y.Panel, {
initializer : function() {
var bb;
// Initialise the element cache.
this._hiddenSiblings = [];
if (this.get('render')) {
this.render();
}
@@ -213,6 +226,7 @@ Y.extend(DIALOGUE, Y.Panel, {
var titlebar, bb;
if (e.attrName === 'visible') {
this.get('maskNode').addClass(CSS.LIGHTBOX);
// Going from visible to hidden.
if (e.prevVal && !e.newVal) {
bb = this.get('boundingBox');
if (this._resizeevent) {
@@ -224,7 +238,13 @@ Y.extend(DIALOGUE, Y.Panel, {
this._orientationevent = null;
}
bb.detach('key', this.keyDelegation);
if (this.get('modal')) {
// Hide this dialogue from screen readers.
this.setAccessibilityHidden();
}
}
// Going from hidden to visible.
if (!e.prevVal && e.newVal) {
// This needs to be done each time the dialog is shown as new dialogs may have been opened.
this.applyZIndex();
@@ -238,6 +258,13 @@ Y.extend(DIALOGUE, Y.Panel, {
}
}
this.keyDelegation();
// Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal.
if (this.get('modal')) {
// Make this dialogue visible to screen readers.
this.setAccessibilityVisible();
}
}
if (this.get('center') && !e.prevVal && e.newVal) {
this.centerDialogue();
@@ -337,13 +364,6 @@ Y.extend(DIALOGUE, Y.Panel, {
this.lockScroll.enableScrollLock(this.shouldResizeFullscreen());
}
// Only do accessibility hiding for modals because the ARIA spec
// says that all ARIA dialogues should be modal.
if (this.get('modal')) {
// Make this dialogue visible to screen readers.
this.setAccessibilityVisible();
}
// Try and find a node to focus on using the focusOnShowSelector attribute.
if (focusSelector !== null) {
focusNode = this.get('boundingBox').one(focusSelector);
@@ -371,11 +391,6 @@ Y.extend(DIALOGUE, Y.Panel, {
}
}
if (this.get('modal')) {
// Hide this dialogue from screen readers.
this.setAccessibilityHidden();
}
// Unlock scroll if the plugin is present.
if (this.lockScroll) {
this.lockScroll.disableScrollLock();
@@ -433,8 +448,6 @@ Y.extend(DIALOGUE, Y.Panel, {
// Get the element that contains this dialogue because we need it
// to filter out from the document.body child elements.
var container = this.get(BASE);
// Keep a record of any elements we change so that they can be reverted later.
this.hiddenSiblings = [];
// We need to get a list containing each sibling element and the shallowest
// non-ancestral nodes in the DOM. We can shortcut this a little by leveraging
@@ -449,7 +462,7 @@ Y.extend(DIALOGUE, Y.Panel, {
if (hidden !== 'true') {
// Save their current state.
node.setData('previous-aria-hidden', hidden);
this.hiddenSiblings.push(node);
this._hiddenSiblings.push(node);
// Hide this node from screen readers.
node.set('aria-hidden', 'true');
@@ -473,7 +486,7 @@ Y.extend(DIALOGUE, Y.Panel, {
container.set('aria-hidden', 'true');
// Restore the sibling nodes back to their original values.
Y.Array.each(this.hiddenSiblings, function(node) {
Y.Array.each(this._hiddenSiblings, function(node) {
var previousValue = node.getData('previous-aria-hidden');
// If the element didn't previously have an aria-hidden attribute
// then we can just remove the one we set.
@@ -486,7 +499,7 @@ Y.extend(DIALOGUE, Y.Panel, {
});
// Clear the cache. No longer need to store these.
this.hiddenSiblings = [];
this._hiddenSiblings = [];
}
}, {
NAME : DIALOGUE_NAME,