editoria11y-1.0.0-alpha8/src/TestNames.php

src/TestNames.php
<?php

namespace Drupal\editoria11y;

/**
 * Provides various reusable strings.
 *
 * @phpstan-consistent-constructor
 */
class TestNames {

  /**
   * Legacy name conversions.
   */
  public static function oldNames() {
    return [
      'altDeadspace' => 'ALT_UNPRONOUNCEABLE',
      'altEmptyLinked' => 'LINK_IMAGE_NO_ALT_TEXT',
      'altImageOf' => 'SUS_ALT',
      'altImageOfLinked' => 'LINK_SUS_ALT',
      'altLong' => 'IMAGE_ALT_TOO_LONG',
      'altLongLinked' => 'LINK_IMAGE_LONG_ALT',
      'altMeaningless' => 'ALT_PLACEHOLDER',
      'altMeaninglessLinked' => 'LINK_PLACEHOLDER_ALT',
      'altMissing' => 'MISSING_ALT',
      'altNull' => 'IMAGE_DECORATIVE',
      'altPartOfLinkWithText' => 'LINK_IMAGE_ALT_AND_TEXT',
      'altURL' => 'ALT_FILE_EXT',
      'altURLLinked' => 'LINK_ALT_FILE_EXT',
      'blockquoteIsShort' => 'QA_BLOCKQUOTE',
      'embedAudio' => 'EMBED_AUDIO',
      'embedCustom' => 'EMBED_GENERAL',
      'embedVideo' => 'EMBED_VIDEO',
      'embedVisualization' => 'EMBED_DATA_VIZ',
      'headingEmpty' => 'HEADING_EMPTY',
      'headingIsLong' => 'HEADING_LONG',
      'headingLevelSkipped' => 'HEADING_SKIPPED_LEVEL',
      'linkDocument' => 'QA_PDF',
      'linkNewWindow' => 'LINK_NEW_TAB',
      'linkNoLabel' => 'LINK_EMPTY_NO_LABEL',
      'linkNoText' => 'LINK_EMPTY',
      'linkTextIsGeneric' => 'LINK_STOPWORD',
      'linkTextIsURL' => 'LINK_URL',
      'tableContainsContentHeading' => 'TABLES_SEMANTIC_HEADING',
      'tableEmptyHeaderCell' => 'TABLES_EMPTY_HEADING',
      'tableNoHeaderCells' => 'TABLES_MISSING_HEADINGS',
      'textPossibleHeading' => 'QA_FAKE_HEADING',
      'textPossibleList' => 'QA_FAKE_LIST',
      'textUppercase' => 'QA_UPPERCASE',
    // @todo but adopt Adam's wording
    // And 'MISSING_ALT_LINKED'?
    // New.
    // QA_DOCUMENT is new and closer.
    ];
  }

  /**
   * Returns key/value pairs of known test names.
   */
  public static function coreNames(): array {
    return [
      'ALT_FILE_EXT' => t("Image's text alternative is a URL"),
      'ALT_MAYBE_BAD' => t('Manual check: alt text may be meaningless'),
      'ALT_PLACEHOLDER' => t('Alt text is meaningless'),
      'ALT_UNPRONOUNCEABLE' => t("Image's text alternative is unpronounceable"),
      'EMBED_AUDIO' => t('Manual check: is an accurate transcript provided?'),
      'EMBED_CUSTOM' => t('Manual check: is this embedded content accessible?'),
      'EMBED_DATA_VIZ' => t('Manual check: is this visualization accessible?'),
      'EMBED_GENERAL' => t('Manual check: is this embedded content accessible?'),
      'EMBED_MISSING_TITLE' => t('Frame missing title attribute'),
      'EMBED_VIDEO' => t('Manual check: is this video accurately captioned?'),
      'HEADING_EMPTY' => t('Heading tag without any text'),
      'HEADING_EMPTY_WITH_IMAGE' => t('Heading has no text, but contains an image'),
      'HEADING_LONG' => t('Manual check: long heading'),
      'HEADING_SKIPPED_LEVEL' => t('Manual check: was a heading level skipped?'),
      'IMAGE_ALT_TOO_LONG' => t('Manual check: very long alternative text'),
      'IMAGE_DECORATIVE' => t('Manual check: image has no alt text'),
      'LINK_ALT_FILE_EXT' => t("Linked image's text alternative is a URL"),
      'LINK_ALT_MAYBE_BAD' => t('Manual check: linked alt text may be meaningless'),
      'LINK_ALT_UNPRONOUNCEABLE' => t('Alt text in linked image is unpronounceable.'),
      'LINK_DOI' => t('APA Style guide recommends using descriptive DOI links'),
      'LINK_EMPTY' => t('Link with no accessible text'),
      'LINK_EMPTY_NO_LABEL' => t('Link with no accessible label'),
      'LINK_IMAGE_ALT_AND_TEXT' => t('Manual check: link contains both text and an image'),
      'LINK_IMAGE_LONG_ALT' => t('Image has no alternative text attribute'),
      'LINK_IMAGE_NO_ALT_TEXT' => t('Linked image has no alt text'),
      'LINK_IMAGE_TEXT' => t('Manual check: Image in a link with text is marked as decorative.'), // @Todo turn off?
      'LINK_NEW_TAB' => t('Manual check: is opening a new window expected?'),
      'LINK_PLACEHOLDER_ALT' => t('Linked alt text is meaningless'),
      'LINK_STOPWORD' => t('Manual check: is this link meaningful and concise?'),
      'LINK_SUS_ALT' => t('Manual check: possibly redundant text in linked image'),
      'LINK_SYMBOLS' => t('Manual check: are the symbols or emoji in this link meaningful?'),
      'LINK_URL' => t('Manual check: is this link text a URL?'),
      'MISSING_ALT' => t('Image has no alternative text attribute'),
      'MISSING_ALT_LINK' => t('Linked image has no alternative text attribute'),
      'MISSING_ALT_LINK_HAS_TEXT' => t('Image in link with text has no alternative text attribute'),
      'QA_BLOCKQUOTE' => t('Manual check: is this a blockquote?'),
      'QA_DOCUMENT' => t('Manual check: linked document'),
      'QA_FAKE_HEADING' => t('Manual check: should this be a heading?'),
      'QA_FAKE_LIST' => t('Manual check: should this have list formatting?'),
      'QA_IN_PAGE_LINK' => t('Broken same-page link'),
      'QA_JUSTIFY' => t('Justified text'),
      'QA_PDF' => t('Manual check: is the linked document accessible?'),
      'QA_STRONG_ITALICS' => t('Manual check: entire paragraph is emphasized'),
      'QA_UNDERLINE' => t('Underlined text'),
      'QA_UPPERCASE' => t('Manual check: is this uppercase text needed?'),
      'SUS_ALT' => t('Manual check: possibly redundant text in alt'),
      'TABLES_EMPTY_HEADING' => t('Empty table header cell'),
      'TABLES_MISSING_HEADINGS' => t('Table has no header cells'),
      'TABLES_SEMANTIC_HEADING' => t('Content heading inside a table'),



      'HEADING_MISSING_ONE' => t('Missing Heading 1'),
      'HEADING_FIRST' => t('The first heading on a page should usually be a Heading 1 or Heading 2'),
      'IMAGE_FIGURE_DECORATIVE' => t('Manual check: image in a figure marked as decorative'),
      'IMAGE_FIGURE_DUPLICATE_ALT' => t('Alt is the same as caption text'),
      'IMAGE_DECORATIVE_CAROUSEL' => t('Image in a carousel or gallery marked as decorative'), // @Todo: move to content?
      'QA_NESTED_COMPONENTS' => t('Nested interactive layout components'),
      'QA_SMALL_TEXT' => t('Small text'),
      'QA_SUBSCRIPT' => t('Manual check: use of subscript or superscript as visual formatting'),

      'BTN_EMPTY' => t('Button purpose is not machine-readable'),
      'BTN_EMPTY_LABELLEDBY' => t('Button has an invalid ARIA label'),
      'BTN_ROLE_IN_NAME' => t('Button name repeats the word "button"'),
      'LINK_EMPTY_LABELLEDBY' => t('Link invalid aria-labelledby attribute'),
      'LINK_FILE_EXT' => t('Link points to a file without warning'),
      'LINK_IDENTICAL_NAME' => t('Manual check: link has identical text as another link but points to a different page'),
      'LINK_STOPWORD_ARIA' => t('Manual check: link text overridden by ARIA that may not be meaningful'),
      'LINK_CLICK_HERE' => t('Manual check: link contains "click here"'),
      'LINK_IMAGE_ALT' => t('Manual check: does the linked image alt describe the destination or action?'),
      'QA_BAD_LINK' => t('Manual check: link target may be invalid'),
      'DUPLICATE_ID' => t('Manual check: duplicate ID'),
      'DUPLICATE_TITLE' => t('Duplicate title attribute'),
      'LABEL_IN_NAME' => t('Visible name different than machine-readable name'),
      'LABELS_ARIA_LABEL_INPUT' => t('Manual check: is there a visible label for this field?'),

      'CONTRAST_ERROR' => t('Text does not have enough contrast to be easily legible'),
      'CONTRAST_ERROR_GRAPHIC' => t('Graphic or icon does not have enough contrast with the background'),
      'CONTRAST_INPUT' => t('Input does not provide enough contrast to be easily legible'),
      'CONTRAST_PLACEHOLDER' => t('Placeholder text does not have enough contrast to be easily legible'),
      'CONTRAST_PLACEHOLDER_UNSUPPORTED' => t('Manual check: does this placeholder text have enough contrast?'),
      'CONTRAST_WARNING' => t('Manual check: does this text have enough contrast?'),
      'CONTRAST_WARNING_GRAPHIC' => t('Manual check: does this graphic or icon have enough contrast?'),

      'HIDDEN_FOCUSABLE' => t('Screen readers told not to speak the name of an interactive element'),
      'EMBED_UNFOCUSABLE' => t('Frame with tabindex="-1" will not be keyboard accessible.'),
      'TABINDEX_ATTR' => t('Provided tabindex value removes element from reading order'),
      'UNCONTAINED_LI' => t('Invalid HTML list'),
      'META_LANG' => t('Meta tag for page language missing'),
      'META_MAX' => t('Meta tag sets max user scaling'),
      'META_REFRESH' => t('Meta tag automatically refreshes page'),
      'META_SCALABLE' => t('Meta tag prevents user scaling'),
      'META_TITLE' => t('Meta tag for page title missing'),
    ];
  }

  /**
   * Returns list of tests defined as content.
   */
  public static function contentTests(): array {
    return [
      'ALT_FILE_EXT',
      'ALT_MAYBE_BAD',
      'ALT_PLACEHOLDER',
      'ALT_UNPRONOUNCEABLE',
      'EMBED_AUDIO',
      'EMBED_CUSTOM',
      'EMBED_DATA_VIZ',
      'EMBED_GENERAL',
      'EMBED_MISSING_TITLE',
      'EMBED_VIDEO',
      'HEADING_EMPTY',
      'HEADING_EMPTY_WITH_IMAGE',
      'HEADING_LONG',
      'HEADING_SKIPPED_LEVEL',
      'IMAGE_ALT_TOO_LONG',
      'IMAGE_DECORATIVE',
      'LINK_ALT_FILE_EXT',
      'LINK_ALT_MAYBE_BAD',
      'LINK_ALT_UNPRONOUNCEABLE',
      'LINK_DOI',
      'LINK_EMPTY',
      'LINK_EMPTY_NO_LABEL',
      'LINK_IMAGE_ALT_AND_TEXT',
      'LINK_IMAGE_LONG_ALT',
      'LINK_IMAGE_NO_ALT_TEXT',
      'LINK_IMAGE_TEXT', // @Todo turn off?
      'LINK_NEW_TAB',
      'LINK_PLACEHOLDER_ALT',
      'LINK_STOPWORD',
      'LINK_SUS_ALT',
      'LINK_SYMBOLS',
      'LINK_URL',
      'MISSING_ALT',
      'MISSING_ALT_LINK',
      'MISSING_ALT_LINK_HAS_TEXT',
      'QA_BLOCKQUOTE',
      'QA_DOCUMENT',
      'QA_FAKE_HEADING',
      'QA_FAKE_LIST',
      'QA_IN_PAGE_LINK',
      'QA_JUSTIFY',
      'QA_PDF',
      'QA_STRONG_ITALICS',
      'QA_UNDERLINE',
      'QA_UPPERCASE',
      'SUS_ALT',
      'TABLES_EMPTY_HEADING',
      'TABLES_MISSING_HEADINGS',
      'TABLES_SEMANTIC_HEADING',
    ];
  }
  public static function contentTestNames(): array {
    return array_intersect_key(self::coreNames(), array_flip(self::contentTests()));
  }

  public static function devTestNames(): array {
    return array_diff(self::coreNames(), self::contentTestNames());
  }

  public static function offByDefault(): array {
    return [
      'CONTRAST_WARNING_GRAPHIC',
      'LINK_CLICK_HERE',
      'LINK_IMAGE_ALT',
    ];
  }

  /**
   * Filters to tests with results in the DB, and adds custom tests.
   *
   * @param string $type
   *   Request 'results' or 'dismissals'.
   */
  public function activeNames(string $type = 'results'): array {
    $staticTests = $this->coreNames();
    $names = [];

    $database = \Drupal::database();

    // $table = $type === 'results' ? 'editoria11y_results' : 'editoria11y_dismissals';
    if ($type == 'results') {
      $results = $database->select('editoria11y_results', 't')
        ->fields('t', ['result_key', 'result_name'])
        ->groupBy('result_key')
        ->groupBy('result_name')
        ->orderBy('result_name')
        ->execute();
    }
    else {
      $results = $database->select('editoria11y_dismissals', 't')
        ->fields('t', ['result_key', 'result_name'])
        ->groupBy('result_key')
        ->groupBy('result_name')
        ->orderBy('result_name')
        ->execute();
    }

    foreach ($results as $result) {
      if (!in_array($result->result_key, $names)) {
        if (in_array($result->result_key, $staticTests)) {
          // Translatable value from known test.
          $names[$result->result_key] = $staticTests[$result->result_key];
        }
        else {
          // Raw value from custom test.
          $names[$result->result_key] = $result->result_name;
        }
      }
    }
    return $names;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc