q( '//*[@role]' ) as $el ) { $tokens = preg_split( '/\s+/', strtolower( trim( $el->getAttribute( 'role' ) ) ) ); $valid = false; foreach ( $tokens as $t ) { if ( isset( $roles[ $t ] ) ) { $valid = true; break; } } if ( ! $valid && '' !== trim( $el->getAttribute( 'role' ) ) ) { $c->add( 'aria-role-invalid', $el, array( 'role' => $el->getAttribute( 'role' ) ) ); } if ( in_array( $tokens[0], array( 'presentation', 'none' ), true ) && $this->focusable( $el ) ) { $c->add( 'presentation-focusable', $el ); } } foreach ( $c->q( '//*[@*[starts-with(name(),"aria-")]]' ) as $el ) { foreach ( $el->attributes as $attr ) { $n = strtolower( $attr->name ); if ( 0 === strpos( $n, 'aria-' ) && ! isset( $attrs[ $n ] ) ) { $c->add( 'aria-attr-invalid', $el, array( 'attribute' => $n ) ); break; } } } foreach ( $c->q( "//*[@aria-hidden='true']" ) as $el ) { if ( Html::is_hidden( $el ) ) { continue; } $bad = $this->focusable( $el ); if ( ! $bad ) { foreach ( $c->q( ".//a[@href] | .//button | .//input[not(@type='hidden')] | .//select | .//textarea | .//*[@tabindex]", $el ) as $d ) { if ( $this->focusable( $d ) && ! Html::is_hidden( $d ) ) { $bad = true; break; } } } if ( $bad ) { $c->add( 'aria-hidden-focusable', $el ); } } foreach ( $c->q( '//*[@tabindex]' ) as $el ) { if ( (int) $el->getAttribute( 'tabindex' ) > 0 ) { $c->add( 'tabindex-positive', $el, array( 'tabindex' => (int) $el->getAttribute( 'tabindex' ) ) ); } } } /** * Is the element in the tab order? * * @param \DOMElement $el Element. * @return bool */ private function focusable( \DOMElement $el ) { if ( $el->hasAttribute( 'disabled' ) ) { return false; } if ( $el->hasAttribute( 'tabindex' ) ) { return (int) $el->getAttribute( 'tabindex' ) >= 0; } $tag = strtolower( $el->tagName ); if ( 'a' === $tag || 'area' === $tag ) { return $el->hasAttribute( 'href' ); } if ( 'input' === $tag ) { return 'hidden' !== strtolower( $el->getAttribute( 'type' ) ); } return in_array( $tag, array( 'button', 'select', 'textarea', 'summary' ), true ); } }