Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(aria): $mdAria should not use texts from aria-hidden nodes
Browse files Browse the repository at this point in the history
* $mdAria is currently just using `textContent` for retrieving the `aria-label`.
  This is not valid, since some child-texts can be hidden in aria (`aria-hidden="true")

* Using a TreeWalker is super elegant and performant.
  The current use of the TreeWalker is supported by all browser we support.

Fixes #7376

Closes #7957
  • Loading branch information
devversion authored and ThomasBurleson committed Apr 11, 2016
1 parent 1fc2939 commit b3cb84d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 6 deletions.
32 changes: 26 additions & 6 deletions src/core/services/aria/aria.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function AriaService($$rAF, $log, $window, $interpolate) {

function expectWithText(element, attrName) {
var content = getText(element) || "";
var hasBinding = content.indexOf($interpolate.startSymbol())>-1;
var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;

if ( hasBinding ) {
expectAsync(element, attrName, function() {
Expand All @@ -62,7 +62,26 @@ function AriaService($$rAF, $log, $window, $interpolate) {
}

function getText(element) {
return (element.text() || "").trim();
element = element[0] || element;
var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
var text = '';

var node;
while (node = walker.nextNode()) {
if (!isAriaHiddenNode(node)) {
text += node.textContent;
}
}

return text.trim() || '';

function isAriaHiddenNode(node) {
while (node.parentNode && (node = node.parentNode) !== element) {
if (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {
return true;
}
}
}
}

function childHasAttribute(node, attrName) {
Expand All @@ -74,17 +93,18 @@ function AriaService($$rAF, $log, $window, $interpolate) {
return (style.display === 'none');
}

if(hasChildren) {
if (hasChildren) {
var children = node.childNodes;
for(var i=0; i<children.length; i++){
for (var i=0; i < children.length; i++) {
var child = children[i];
if(child.nodeType === 1 && child.hasAttribute(attrName)) {
if(!isHidden(child)){
if (child.nodeType === 1 && child.hasAttribute(attrName)) {
if (!isHidden(child)) {
hasAttr = true;
}
}
}
}

return hasAttr;
}
}
31 changes: 31 additions & 0 deletions src/core/services/aria/aria.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,37 @@ describe('$mdAria service', function() {
button.remove();

}));

it('should correctly retrieve the aria-label text', inject(function($compile, $rootScope, $mdAria) {
var container = $compile(
'<div>' +
'PLAIN' +
'<span>SPAN</span>' +
'<div>DIV</div>' +
'</div>'
)($rootScope);

$mdAria.expectWithText(container, 'aria-label');

expect(container[0].textContent).toBe('PLAINSPANDIV');
expect(container.attr('aria-label')).toBe('PLAINSPANDIV');
}));

it('should ignore aria-hidden texts when retrieving aria-label', inject(function($compile, $rootScope, $mdAria) {
var container = $compile(
'<div>' +
'PLAIN' +
'<span aria-hidden="true">SPAN</span>' +
'<div aria-hidden="true">DIV</div>' +
'</div>'
)($rootScope);

$mdAria.expectWithText(container, 'aria-label');

expect(container[0].textContent).toBe('PLAINSPANDIV');
expect(container.attr('aria-label')).toBe('PLAIN');
}));

});

});

0 comments on commit b3cb84d

Please sign in to comment.