q( "//input[not(translate(@type,'HIDENSUBMTRCLOKFY','hidensubmtrcloky')='hidden' or translate(@type,'SUBMIT','submit')='submit' or translate(@type,'BUTON','buton')='button' or translate(@type,'RESET','reset')='reset' or translate(@type,'IMAGE','image')='image')] | //select | //textarea" ); $labels = array(); foreach ( $c->q( '//label[@for]' ) as $l ) { if ( '' !== Html::clean( Html::text_of( $l ) ) ) { $labels[ $l->getAttribute( 'for' ) ][] = $l; } } $radios = array(); $checks = array(); foreach ( $controls as $in ) { if ( Html::is_hidden( $in ) || 'true' === $in->getAttribute( 'aria-hidden' ) || $in->hasAttribute( 'disabled' ) ) { continue; } $tag = strtolower( $in->tagName ); $type = strtolower( $in->getAttribute( 'type' ) ); $id = $in->getAttribute( 'id' ); $label_text = ''; if ( '' !== $id && isset( $labels[ $id ] ) ) { $label_text = Html::clean( Html::text_of( $labels[ $id ][0] ) ); } $wrap = $c->q( 'ancestor::label[1]', $in ); if ( $wrap && '' === $label_text ) { $label_text = Html::clean( Html::text_of( $wrap[0] ) ); } $aria = trim( $in->getAttribute( 'aria-label' ) ) . trim( $in->getAttribute( 'aria-labelledby' ) ); $name = '' !== $label_text || '' !== $aria || '' !== trim( $in->getAttribute( 'title' ) ); if ( ! $name ) { if ( '' !== trim( $in->getAttribute( 'placeholder' ) ) ) { $c->add( 'input-placeholder-only', $in ); } else { $c->add( 'input-no-label', $in ); } } if ( 'radio' === $type ) { $radios[ $in->getAttribute( 'name' ) ][] = $in; } if ( 'checkbox' === $type ) { $checks[ $in->getAttribute( 'name' ) ][] = $in; } // Autocomplete on personal data fields. if ( 'select' !== $tag && ! in_array( $type, array( 'radio', 'checkbox', 'file', 'search', 'range', 'color' ), true ) ) { $ac = strtolower( trim( $in->getAttribute( 'autocomplete' ) ) ); if ( '' === $ac || 'off' === $ac ) { $key = strtolower( preg_replace( '/[\[\]]/', '', $in->getAttribute( 'name' ) ) ); $idkey = strtolower( $id ); $map = $phrases['personalAutocomplete']; $token = ''; if ( 'email' === $type ) { $token = 'email'; } elseif ( 'tel' === $type ) { $token = 'tel'; } elseif ( isset( $map[ $key ] ) ) { $token = $map[ $key ]; } elseif ( isset( $map[ $idkey ] ) ) { $token = $map[ $idkey ]; } if ( '' !== $token && 'textarea' !== $tag ) { $c->add( 'input-autocomplete-missing', $in, array( 'suggested' => $token ) ); } } } // Required only shown visually. if ( '' !== $label_text && ! $in->hasAttribute( 'required' ) && 'true' !== $in->getAttribute( 'aria-required' ) ) { if ( preg_match( '/\*|\(required\)|\brequired\b/i', $label_text ) ) { $c->add( 'required-not-programmatic', $in ); } } } foreach ( array( $radios, $checks ) as $set ) { foreach ( $set as $name => $group ) { $multi = count( $group ) > 1 && '' !== $name; if ( ! $multi ) { continue; } $first = $group[0]; if ( ! $c->q( "ancestor::fieldset | ancestor::*[@role='group' or @role='radiogroup']", $first ) ) { $c->add( 'group-no-fieldset', $first, array( 'count' => count( $group ) ) ); } } } } }