accessibility-8.x-1.x-dev/modules/accessibility_testswarm/accessibility_testswarm.module

modules/accessibility_testswarm/accessibility_testswarm.module
<?php


use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\Config;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Utility\ThemeRegistry;
use Drupal\Core\Theme\ThemeSettings;

/**
 * Implements hook_page_build().
 */
function accessibility_testswarm_page_build(&$page) {
  $library_path = libraries_get_path('quail');
  drupal_add_js(array('accessibility_testswarm' => array('quail_path' => $library_path .'quail/src/', 'path' => drupal_get_path('module', 'accessibility_testswarm'))), 'setting');
  return $page;
}

function accessibility_testswarm_menu() {
  $items = array();
  
  $items['admin/config/accessibility/testswarm'] = array(
    'title' => 'TestSwarm',
    'description' => 'Configure paths for automated accessibility testing.',
    'route_name' => 'accessibility_testswarm_admin_form',
  );
  
  return $items;
}

/**
 *	Implements hook_testswarm_tests();
 */
function accessibility_testswarm_testswarm_tests() {
  if($paths = cache()->get('accessibility_testswarm:paths')) {
    $paths = $paths->data;
  }
  else {
    $config = Drupal::config('accessibility.accessibility_testswarm');
    $paths = ($config->get('check_all')) ?
      module_invoke_all('accessibility_testswarm_paths') :
      explode("\n", $config->get('paths'));
    array_walk($paths, 'trim');
    cache()->set('accessibility_testswarm:paths', $paths);
  }
  if(!$paths || !count($paths)) {
  	return;
  }
  $library_path = libraries_get_path('quail');
  $tests = array();
  foreach($paths as $path) {
	  $tests[str_replace('/', '_', $path)] = array(
      'js' => array(
        $library_path . '/src/quail.js',
        drupal_get_path('module', 'accessibility_testswarm') . '/js/accessibility_testswarm.js'
      ),
      'description' => $path,
      'module' => 'accessibility_testswarm',
      'path' => $path,
      'dependencies' => array(
        array('testswarm', 'jquery.simulate'),
      ),
      'permissions' => array('access content')
		);
	}
	return $tests;
}

/**
 * Implements hook_menu_alter().
 */
function accessibility_testswarm_menu_alter(&$items) {
	$items['testswarm-tests/detail/%/tests/%']['page callback'] = 'accessibility_testswarm_test_details_tests';
  $items['testswarm-tests/detail/%/tests/%']['file'] = 'accessibility_testswarm.pages.inc';
  $items['testswarm-tests/detail/%/tests/%']['file path'] = drupal_get_path('module', 'accessibility_testswarm');
  
}

/**
 * Implements hook_accessibility_testswarm_paths().
 */
function accessibility_testswarm_accessibility_testswarm_paths() {
  module_load_include('inc', 'accessibility_testswarm');
  $paths = module_invoke_all('menu');
  $filters = _accessibility_testswarm_path_filters();
  $absolute_paths = _accessibility_testswarm_path_values();
  $test_paths = array('<front>');
  foreach($paths as $path => $menu) {
    if((isset($menu['theme callback']) && $menu['theme callback'] == 'ajax_base_page_theme') ||
       (isset($menu['type']) && $menu['type'] == MENU_DEFAULT_LOCAL_TASK)) {
      continue;
    }
    if(isset($absolute_paths[$path])) {
      if(is_array($absolute_paths[$path])) {
        $test_paths = array_merge($test_paths, $absolute_paths[$path]);
      }
      elseif($absolute_paths[$path]) {
        $test_paths[] = $absolute_paths[$path];
      }
    }
    elseif((!isset($menu['page arguments']) || !count($menu['page arguments'])) && 
         strpos($path, '%') === FALSE && strpos($path, '{') === FALSE) {
      //plain path, no arguments
      $test_paths[] = $path;
    }
    else {
      $path = explode('/', $path);
      foreach($path as $key => $segment) {
        if(isset($filters[$segment])) {
          if(is_string($filters[$segment]) && function_exists($filters[$segment])) {
            $path[$key] = $filters[$segment]();
          }
          else {
            $path[$key] = $filters[$segment];
          }
        }
      }
      foreach($path as $segment) {
        if(is_array($segment)) {
          foreach($segment as $argument_key => $argument) {
            $string = array();
            $set = true;
            foreach($path as $segment) {
              if(is_array($segment)) {
                if(!isset($segment[$argument_key])) {
                  $set = false;
                }
                $string[] = $segment[$argument_key];
              }
              else {
                $string[] = $segment;
              }
            }
            if($set && count($string)) {
              $test_paths[] = implode('/', $string);
            }
          }
        }
      }
    }
  }
  return array_unique($test_paths);
}

/**
 * Implements hook_testswarm_test_alter().
 * See patch in issue #.
 */
function accessibility_testswarm_testswarm_test_alter(&$called_tests) {
  $request = Drupal::request();
  if (!$request->get('caller') || !$request->get('token')) {
    return;
  }
  $tests = $request->get('tests') ? $request->get('tests') : array();
  $logs = $request->get('log') ? $request->get('log') : array();
  
  // @to-do this is a terribly hackish way to get access to the test run ID
  $query = \Drupal::database()->select('testswarm_test_run', 'd');
	$query->addExpression('MAX(id)');
	$test_run_id = $query->execute()->fetchField();
  $test_run_id = ($test_run_id) ? $test_run_id : 0;
  foreach($tests as $test) {
  	foreach($logs['default'][$test['name']] as $attempt) {
  		if($attempt['result'] == 'false') {
  			$data = $attempt['accessibility_testswarm'];
        foreach($data as $item) {
          $hook = (is_array($item['theme']['name'])) 
                    ? array_pop($item['theme']['name'])
                    : $item['theme']['name'];
          \Drupal::database()->insert('accessibility_testswarm_test_detail')
    			  ->fields(array(
    			  	'tri'  => $test_run_id,
    			  	'test' => $attempt['message'],
    			  	'hook' => $hook,
              'type' => $item['theme']['type'],
              'theme_item' => $item['theme']['used'],
              'element' => $item['element']
    			  ))
    			  ->execute();
  		  }
      }
	  }
	}
}

/**
 * Implements hook_theme_registry_alter().
 */
function accessibility_testswarm_theme_registry_alter(&$theme_registry) {
  foreach ($theme_registry as $hook => $data) {
    $theme_registry[$hook] = array(
      'function' => 'accessibility_testswarm_catch_function',
      'theme path' => $data['theme path'],
      'variables' => array(),
      'original_theme' => $data,
    );
  }
}

/**
 * Theme callback function that sets up global variables for storing theme
 * information.
 */
function accessibility_testswarm_catch_function() {
  $trace = debug_backtrace(FALSE);
  $hook = $trace[1]['args'][0];
  if (sizeof($trace[1]['args']) > 1) {
    $variables =  $trace[1]['args'][1];
  }
  else {
    $variables = array();
  }
  $key = md5(serialize($hook));
  $meta = array(
    'name' => $hook,
    'process functions' => array(),
    'preprocess functions' => array(),
    'suggestions' => array(),
    'variables' => $variables,
    'suggested_hook' => '',
    'template_file' => '',
    'extension' => '',
    'type' => '',
  );

  $return = accessibility_testswarm_theme_twin($hook, $variables, $meta);

  if (!empty($return) && !is_array($return) && !is_object($return) && user_access('access devel information')) {

    if (!in_array($hook, array('html_tag', 'options_none'))) {
      $return = '<span class="-a11y-testswarm" data-theme-key="' . $key .'">' . $return .'</span>';
    }

    if ($meta['type'] == 'function') {
      global $theme;
      // If the function hasn't been overwritten by the current theme, add it
      // as a suggestion.
      if ("{$theme}_{$meta['suggested_hook']}()" != $meta['used']) {
        $meta['suggestions'][] = $meta['suggested_hook'];
      }
      foreach ($meta['suggestions'] as $delta => $suggestion) {
        $meta['suggestions'][$delta] = "{$theme}_{$suggestion}()";
      }

    }
    else {
      // If the template hasn't been overwritten by the theme, add it as a
      // suggestion.
      if (FALSE === strpos($meta['template_file'], path_to_theme() . '/')) {
        $meta['suggestions'][] = $meta['suggested_hook'];
      }
      foreach ($meta['suggestions'] as $delta => $suggestion) {
        $meta['suggestions'][$delta] = strtr($suggestion, '_', '-') . $meta['extension'];
      }
    }

    $GLOBALS['accessibility_testswarm_theme_calls'][$key] = array(
      'name' => $meta['name'],
      'used' => ($meta['type'] == 'function') ? $meta['used'] : $meta['template_file'],
      'type' => $meta['type'],
      'candidates' => $meta['suggestions'],
      'preprocessors' => $meta['preprocess functions'],
      'processors' => $meta['process functions']
    );
  }
  return $return;
}

/**
 * Implements hook_page_alter().
 */
function accessibility_testswarm_page_alter(&$page) {
  $page['#post_render'][] = 'accessibility_testswarm_post_process_page';
}

/**
 * Page callback to inject theme indexes into Drupal.settings.
 */
function accessibility_testswarm_post_process_page($page, $elements) {
  if (empty($_GET['testswarm-test'])) {
    return $page;
  }
  if (!empty($GLOBALS['accessibility_testswarm_theme_calls']) && $_SERVER['REQUEST_METHOD'] != 'POST') {
    $javascript = '<script type="text/javascript">jQuery.extend(Drupal.settings, {"accessibility_testswarm_theme" : ' . drupal_json_encode($GLOBALS['accessibility_testswarm_theme_calls']) . "});</script>\n";
    $page = preg_replace('#</body>#', "\n$javascript\n</body>", $page, 1);
  }
  return $page;
}

/**
 * A mirror of the theme() function that resets a theme's callback
 * to the original and also sets additional meta data.
 */
function accessibility_testswarm_theme_twin($hook, $variables, &$meta) {
  static $default_attributes;
  // If called before all modules are loaded, we do not necessarily have a full
  // theme registry to work with, and therefore cannot process the theme
  // request properly. See also _theme_load_registry().
  if (!drupal_container()->get('module_handler')->isLoaded() && !defined('MAINTENANCE_MODE')) {
    throw new Exception(t('theme() may not be called until all modules are loaded.'));
  }

  $hooks = theme_get_registry(FALSE);

  // If an array of hook candidates were passed, use the first one that has an
  // implementation.
  if (is_array($hook)) {
    foreach ($hook as $candidate) {
      if (isset($hooks[$candidate])) {
        break;
      }
    }
    $hook = $candidate;
  }
  // Save the original theme hook, so it can be supplied to theme variable
  // preprocess callbacks.
  $original_hook = $hook;

  // If there's no implementation, check for more generic fallbacks. If there's
  // still no implementation, log an error and return an empty string.
  if (!isset($hooks[$hook])) {
    // Iteratively strip everything after the last '__' delimiter, until an
    // implementation is found.
    while ($pos = strrpos($hook, '__')) {
      $hook = substr($hook, 0, $pos);
      if (isset($hooks[$hook])) {
        break;
      }
    }
    if (!isset($hooks[$hook])) {
      // Only log a message when not trying theme suggestions ($hook being an
      // array).
      if (!isset($candidate)) {
        watchdog('theme', 'Theme hook %hook not found.', array('%hook' => $hook), WATCHDOG_WARNING);
      }
      return '';
    }
  }

  $info = $hooks[$hook]['original_theme'];
  global $theme_path;
  $temp = $theme_path;
  // point path_to_theme() to the currently used theme path:
  $theme_path = $info['theme path'];

  // Include a file if the theme function or variable processor is held
  // elsewhere.
  if (!empty($info['includes'])) {
    foreach ($info['includes'] as $include_file) {
      include_once DRUPAL_ROOT . '/' . $include_file;
    }
  }

  // If a renderable array is passed as $variables, then set $variables to
  // the arguments expected by the theme function.
  if (isset($variables['#theme']) || isset($variables['#theme_wrappers'])) {
    $element = $variables;
    $variables = array();
    if (isset($info['variables'])) {
      foreach (array_keys($info['variables']) as $name) {
        if (isset($element["#$name"])) {
          $variables[$name] = $element["#$name"];
        }
      }
    }
    else {
      $variables[$info['render element']] = $element;
      // Give a hint to render engines to prevent infinite recursion.
      $variables[$info['render element']]['#render_children'] = TRUE;
    }
  }

  // Merge in argument defaults.
  if (!empty($info['variables'])) {
    $variables += $info['variables'];
  }
  elseif (!empty($info['render element'])) {
    $variables += array($info['render element'] => array());
  }
  // Supply original caller info.
  $variables += array(
    'theme_hook_original' => $original_hook,
  );

  // Invoke the variable processors, if any. The processors may specify
  // alternate suggestions for which hook's template/function to use. If the
  // hook is a suggestion of a base hook, invoke the variable processors of
  // the base hook, but retain the suggestion as a high priority suggestion to
  // be used unless overridden by a variable processor function.
  if (isset($info['base hook'])) {
    $base_hook = $info['base hook'];
    $base_hook_info = $hooks[$base_hook];
    // Include files required by the base hook, since its variable processors
    // might reside there.
    if (!empty($base_hook_info['includes'])) {
      foreach ($base_hook_info['includes'] as $include_file) {
        include_once DRUPAL_ROOT . '/' . $include_file;
      }
    }
    if (isset($base_hook_info['preprocess functions']) || isset($base_hook_info['process functions'])) {
      $variables['theme_hook_suggestion'] = $hook;
      $hook = $base_hook;
      $info = $base_hook_info;
    }
  }
  if (isset($info['preprocess functions']) || isset($info['process functions'])) {
    $variables['theme_hook_suggestions'] = array();
    foreach (array('preprocess functions', 'process functions') as $phase) {
      if (!empty($info[$phase])) {
        foreach ($info[$phase] as $processor_function) {
          if (function_exists($processor_function)) {
            // We don't want a poorly behaved process function changing $hook.
            $hook_clone = $hook;
            $processor_function($variables, $hook_clone, $info);
          }
        }
      }
    }
    // If the preprocess/process functions specified hook suggestions, and the
    // suggestion exists in the theme registry, use it instead of the hook that
    // theme() was called with. This allows the preprocess/process step to
    // route to a more specific theme hook. For example, a function may call
    // theme('node', ...), but a preprocess function can add 'node__article' as
    // a suggestion, enabling a theme to have an alternate template file for
    // article nodes. Suggestions are checked in the following order:
    // - The 'theme_hook_suggestion' variable is checked first. It overrides
    //   all others.
    // - The 'theme_hook_suggestions' variable is checked in FILO order, so the
    //   last suggestion added to the array takes precedence over suggestions
    //   added earlier.
    $suggestions = array();
    if (!empty($variables['theme_hook_suggestions'])) {
      $suggestions = $variables['theme_hook_suggestions'];
    }
    if (!empty($variables['theme_hook_suggestion'])) {
      $suggestions[] = $variables['theme_hook_suggestion'];
    }
    foreach (array_reverse($suggestions) as $suggestion) {
      if (isset($hooks[$suggestion])) {
        $info = $hooks[$suggestion];
        break;
      }
    }
  }

  // Generate the output using either a function or a template.
  $output = '';
  if (isset($info['function'])) {
    $meta['type'] = 'function';
    $meta['used'] = $info['function'] . '()';
    if (function_exists($info['function'])) {
      $output = $info['function']($variables);
    }
  }
  else {
    $meta['type'] = 'template';
    // Default render function and extension.
    $render_function = 'twig_render_template';
    $extension = '.html.twig';

    // The theme engine may use a different extension and a different renderer.
    global $theme_engine;
    if (isset($theme_engine)) {
      if ($info['type'] != 'module') {
        if (function_exists($theme_engine . '_render_template')) {
          $render_function = $theme_engine . '_render_template';
        }
        $extension_function = $theme_engine . '_extension';
        if (function_exists($extension_function)) {
          $extension = $extension_function();
        }
      }
    }
    $meta['extension'] = $extension;
    // In some cases, a template implementation may not have had
    // template_preprocess() run (for example, if the default implementation is
    // a function, but a template overrides that default implementation). In
    // these cases, a template should still be able to expect to have access to
    // the variables provided by template_preprocess(), so we add them here if
    // they don't already exist. We don't want the overhead of running
    // template_preprocess() twice, so we use the 'directory' variable to
    // determine if it has already run, which while not completely intuitive,
    // is reasonably safe, and allows us to save on the overhead of adding some
    // new variable to track that.
    if (!isset($variables['directory'])) {
      $default_template_variables = array();
      template_preprocess($default_template_variables, $hook);
      $variables += $default_template_variables;
    }
    if (!isset($default_attributes)) {
      $default_attributes = new Attribute();
    }
    foreach (array('attributes', 'title_attributes', 'content_attributes') as $key) {
      if (isset($variables[$key]) && !($variables[$key] instanceof Attribute)) {
        if ($variables[$key]) {
          $variables[$key] = new Attribute($variables[$key]);
        }
        else {
          // Create empty attributes.
          $variables[$key] = clone $default_attributes;
        }
      }
    }

    // Render the output using the template file.
    $template_file = $info['template'] . $extension;
    $meta['used'] = $template_file;
    if (isset($info['path'])) {
      $template_file = $info['path'] . '/' . $template_file;
    }

    $meta['template_file'] = $template_file;
    $output = $render_function($template_file, $variables);
  }

  // restore path_to_theme()
  $theme_path = $temp;
  return $output;
}

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

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