You are here

cf_theme.module in Common Functionality 7

Same filename and directory in other branches
  1. 7.2 modules/cf_theme/cf_theme.module

File

modules/cf_theme/cf_theme.module
View source
<?php

/**
 * Returns an array of variables to be used by a given theme.
 *
 * Why:
 *   Theme *.tpl.php files should not ever have to call generate or perform
 *   isset()/empty() checks to prevent errors from happening.
 *   All of this work should be done in the template.php.
 *   There is not a standard way of doing this such that other modules and
 *   themes can hook into.
 *   This also allows custom modules to alter themes without having to hack or
 *   alter any existing theme that supports these functions.
 *
 * @param array $variables
 *   The variables array from the theme template functions.
 * @param array $function_history
 *   (optional) An array of function names, ie:
 *   array('0' => 'my_function_name').
 *
 * @return array
 *   An array of variables to be provided to the calling theme.
 */
function cf_theme_get_variables(array &$variables, array $function_history = array()) {
  $cf =& drupal_static(__FUNCTION__, array());
  if (!empty($cf)) {
    return $cf;
  }
  $cf['css'] = array();
  $cf['meta'] = array(
    'charset' => 'UTF-8',
    'content' => NULL,
    'http-equiv' => array(),
    'name' => array(),
  );
  $cf['agent'] = array(
    'machine_name' => 'unknown',
    'human_name' => 'unknown',
    'major_version' => 'unknown',
    'engine' => 'unknown',
    'raw' => '',
  );
  $cf['breadcrumb'] = array();
  $cf['markup_css'] = array(
    'body' => array(
      'id' => '',
      'class' => '',
    ),
    'content' => array(
      'id' => '',
      'class' => '',
    ),
  );
  $cf['at'] = array(
    'machine_name' => '',
    'human_name' => '',
    'url' => '',
    'base' => '',
    'path' => '',
    'alias' => '',
    'css' => '',
  );
  $cf['date'] = array(
    'enabled' => FALSE,
    'year' => '',
    'month' => '',
    'day' => '',
    'week' => '',
    'hour' => '',
    'minute' => '',
    'timezone' => '',
  );
  $cf['theme'] = array(
    'path' => '',
    'machine_name' => '',
    'human_name' => '',
  );
  $cf['is'] = array();
  $cf['is_data'] = array();
  $cf['show'] = array();
  $cf['data'] = array();
  foreach (array(
    'front',
    'admin',
    'using_database',
    'node',
    'emergency',
    'maintenance',
    'unsupported',
    'debug',
    'overlay',
    'logged_in',
    'published',
    'unpublished',
    'promoted',
    'sticky',
  ) as $key) {
    $cf['is'][$key] = FALSE;
    $cf['is_data'][$key] = array();
  }
  $user = cf_current_user();

  // set the request time if it exists
  if (empty($_SERVER['REQUEST_TIME'])) {
    $cf['request'] = microtime();
  }
  else {
    $cf['request'] = $_SERVER['REQUEST_TIME'];
  }

  // do not cache maintenance mode pages.
  $maintenace_mode = variable_get('maintenance_mode', 0);
  if ($maintenace_mode || !empty($MAINTENANCE_MODE)) {
    $cf['meta']['name']['googlebot'] = 'noarchive,noindex,nofollow,nosnippet';
    $cf['meta']['name']['robots'] = 'NONE';
    $cf['meta']['http-equiv']['cache-control'] = 'no-cache';
    $cf['is']['maintenance'] = TRUE;
  }

  // set the user agent
  if (function_exists('get_browser') && !empty($_SERVER['HTTP_USER_AGENT'])) {
    $browser_details = get_browser(null, true);
    $cf['agent']['raw'] = $_SERVER['HTTP_USER_AGENT'];
    if (!empty($cf['agent']['raw'])) {

      // Gecko
      $matches = array();
      $result = preg_match('/ Gecko\\b/i', $cf['agent']['raw'], $matches);
      if ($result > 0) {
        $cf['agent']['engine'] = 'gecko';
      }

      // webkit
      $matches = array();
      $result = preg_match('/ AppleWebKit\\b/i', $cf['agent']['raw'], $matches);
      if ($result > 0) {
        $cf['agent']['engine'] = 'webkit';
      }
    }
    if (!empty($browser_details['browser'])) {
      if ($browser_details['browser'] != 'Default Browser') {
        $cf['agent']['machine_name'] = strtolower($browser_details['browser']);
        $cf['agent']['human_name'] = $browser_details['browser'];
      }
    }
    if (!empty($browser_details['majorver'])) {
      $cf['agent']['major_version'] = $browser_details['majorver'];
    }
    switch ($cf['agent']['machine_name']) {
      case 'firefox':
        if ($cf['agent']['major_version'] < 3) {
          $cf['is']['unsupported'] = TRUE;
        }
        $cf['agent']['human_name'] = 'Firefox';
        $cf['agent']['engine'] = 'gecko';
        break;
      case 'mozilla':
        $cf['agent']['human_name'] = 'Mozilla';
        $cf['agent']['engine'] = 'gecko';
        break;
      case 'ie':
        $cf['agent']['human_name'] = 'Internet Explorer';
        $cf['agent']['engine'] = 'trident';
        break;
      case 'opera':
        $cf['agent']['human_name'] = 'Opera';
        $cf['agent']['engine'] = 'presto';
        break;
      case 'chrome':
        $cf['agent']['human_name'] = 'Google Chrome';
        $cf['agent']['engine'] = 'webkit';
        break;
      default:
        if (!empty($cf['agent']['raw'])) {
          $matches = array();
          $result = preg_match('/ Midori\\b/i', $cf['agent']['raw'], $matches);
          if ($result > 0) {
            $cf['agent']['machine_name'] = 'midori';
            $cf['agent']['human_name'] = 'Midori';
            $cf['agent']['engine'] = 'webkit';
          }
          if ($result == 0) {
            $matches = array();
            $result = preg_match('/ Konqueror\\b/i', $cf['agent']['raw'], $matches);
            if ($result > 0) {
              $cf['agent']['machine_name'] = 'konqueror';
              $cf['agent']['human_name'] = 'Konqueror';
              $cf['agent']['engine'] = 'gecko';
            }
          }
          if ($result == 0) {
            $matches = array();
            $result = preg_match('/ Ephiphany\\b/i', $cf['agent']['raw'], $matches);
            if ($result > 0) {
              $cf['agent']['machine_name'] = 'ephiphany';
              $cf['agent']['human_name'] = 'Ephiphany';
              $cf['agent']['engine'] = 'gecko';
            }
          }

          // both ephiphany and konqueror have gecko AND webkit variants, try to detect webkit ones
          if ($cf['agent']['machine_name'] == 'ephiphany' || $cf['agent']['machine_name'] == 'konqueror') {
            $matches = array();
            $result = preg_match('/ KHTML\\b/i', $cf['agent']['raw'], $matches);
            if ($result > 0) {
              $cf['agent']['engine'] = 'webkit';
            }
          }
        }
        break;
    }
  }

  // set frontpage defaults
  if (drupal_is_front_page()) {
    $cf['is']['front'] = TRUE;
    $cf['meta']['name']['robots'] = 'INDEX,FOLLOW';
  }
  if (!empty($variables['is_admin'])) {
    $cf['is']['admin'] = TRUE;
  }
  if (is_object($user) && property_exists($user, 'uid') && $user->uid > 0) {
    $cf['is']['logged_in'] = TRUE;
    $cf['is_data']['logged_in']['user'] =& $user;
  }
  if (!empty($variables['db_is_active'])) {
    $cf['is']['using_database'] = TRUE;
    $cf['is_data']['using_database']['database'] = db_driver();
  }
  $node_object = NULL;
  if (isset($variables['node'])) {
    $node_object =& $variables['node'];
  }
  else {
    if (isset($variables['page']) && is_array($variables['page']) && !empty($variables['page']['#type']) && isset($variables['page']['content']['system_main']['#node']) && is_object($variables['page']['content']['system_main']['#node'])) {
      $node_object =& $variables['page']['content']['system_main']['#node'];
    }
  }
  if (is_object($node_object) && property_exists($node_object, 'type') && !empty($node_object->type)) {
    if (property_exists($node_object, 'nid') && !empty($node_object->nid)) {
      $cf['is']['node'] = TRUE;
      $cf['is_data']['node']['object'] =& $node_object;
      if ($cf['is_data']['node']['object']->status == NODE_PUBLISHED) {
        $cf['is']['published'] = TRUE;
        $cf['is_data']['published']['value'] = $node_object->status;
      }
      if ($cf['is_data']['node']['object']->status != NODE_PUBLISHED) {
        $cf['is']['unpublished'] = TRUE;
        $cf['is_data']['unpublished']['value'] = $node_object->status;
      }
      if ($cf['is_data']['node']['object']->promote == NODE_PROMOTED) {
        $cf['is']['promoted'] = TRUE;
        $cf['is_data']['promoted']['value'] = $node_object->promote;
      }
      if ($cf['is_data']['node']['object']->promote == NODE_STICKY) {
        $cf['is']['sticky'] = TRUE;
        $cf['is_data']['sticky']['value'] = $node_object->sticky;
      }
    }
  }
  if (module_exists('overlay')) {
    $overlay_mode = overlay_get_mode();
    if ($overlay_mode == 'child') {
      $cf['is']['overlay'] = TRUE;
    }
  }

  // add url specific css
  global $base_url;
  global $base_dir;
  $cf['at']['machine_name'] = preg_replace('/^.*\\/\\//i', '', $base_url);
  $cf['at']['human_name'] = variable_get('site_name');
  $cf['at']['url'] = $base_url;
  $cf['at']['base'] = $base_dir;
  if (!is_string($cf['at']['machine_name'])) {
    $cf['at']['machine_name'] = '';
  }
  if (!empty($cf['at']['machine_name'])) {
    $cf['at']['css'] = ' at-' . cf_theme_safe_css_string_part($cf['at']['machine_name']);
  }
  if (function_exists('current_path')) {
    $cf['at']['path'] = current_path();
  }
  else {
    if (isset($_GET['q'])) {
      $cf['at']['path'] = $_GET['q'];
    }
  }
  if (function_exists('request_path')) {
    $cf['at']['alias'] = request_path();
  }
  else {
    if (isset($_GET['q'])) {
      $cf['at']['alias'] = $_GET['q'];
    }
  }
  if (!empty($cf['at']['path'])) {
    $cf['at']['css'] .= ' path-' . cf_theme_safe_css_string_part($cf['at']['path']);
  }
  if (!empty($cf['at']['alias'])) {
    $cf['at']['css'] .= ' alias-' . cf_theme_safe_css_string_part($cf['at']['alias']);
  }

  // Add date-specific css
  $cf['date']['year'] = date('Y', REQUEST_TIME);
  $cf['date']['month'] = date('m', REQUEST_TIME);
  $cf['date']['day'] = date('d', REQUEST_TIME);
  $cf['date']['week'] = date('W', REQUEST_TIME);
  $cf['date']['hour'] = date('H', REQUEST_TIME);
  $cf['date']['minute'] = date('i', REQUEST_TIME);
  $cf['date']['timezone'] = date('O', REQUEST_TIME);
  drupal_alter('cf_theme_get_variables', $cf, $variables);

  // populate the body and content css tags
  foreach ($cf['is'] as $key => $value) {
    if ($value === TRUE) {
      $cf['markup_css']['body']['class'] .= ' is-' . $key;
      $cf['markup_css']['content']['class'] .= ' is-' . $key;
    }
  }
  $cf['markup_css']['body']['class'] .= $cf['at']['css'];
  $cf['markup_css']['content']['class'] .= $cf['at']['css'];
  if (!empty($cf['agent']['machine_name'])) {
    $cf['markup_css']['body']['class'] .= ' agent-name-' . cf_theme_safe_css_string_part($cf['agent']['machine_name']);
    $cf['markup_css']['content']['class'] .= ' agent-name-' . cf_theme_safe_css_string_part($cf['agent']['machine_name']);
  }
  if (!empty($cf['agent']['engine'])) {
    $cf['markup_css']['body']['class'] .= ' agent-engine-' . cf_theme_safe_css_string_part($cf['agent']['engine']);
    $cf['markup_css']['content']['class'] .= ' agent-engine-' . cf_theme_safe_css_string_part($cf['agent']['engine']);
  }
  if ($cf['is']['node']) {
    $cf['markup_css']['body']['class'] .= ' node_type-' . cf_theme_safe_css_string_part($cf['is_data']['node']['object']->type);
    $cf['markup_css']['content']['class'] .= ' node_type-' . cf_theme_safe_css_string_part($cf['is_data']['node']['object']->type);
  }
  if ($cf['date']['enabled']) {
    foreach (array(
      'year',
      'month',
      'day',
      'week',
      'hour',
      'minute',
    ) as $key) {
      if (!empty($cf['date'][$key])) {
        $cf['markup_css']['body']['class'] .= ' date-' . $key . '-' . cf_theme_safe_css_string_part($cf['date'][$key]);
        $cf['markup_css']['content']['class'] .= ' date-' . $key . '-' . cf_theme_safe_css_string_part($cf['date'][$key]);
      }
    }
    if (!empty($cf['date']['timezone'])) {
      $timezone = preg_replace('/^\\+/i', 'P', $cf['date']['timezone']);
      $timezone = preg_replace('/^\\-/i', 'N', $timezone);
      if (is_string($timezone)) {
        $timezone_css = cf_theme_safe_css_string_part($timezone);
        if ($timezone_css !== FALSE) {
          $cf['markup_css']['body']['class'] .= ' date-timezone-' . $timezone_css;
          $cf['markup_css']['content']['class'] .= ' date-timezone-' . $timezone_css;
        }
      }
    }
  }
  return $cf;
}

/**
 * Properly generates html headers based on the contents of the $cf parameter.
 *
 * This will auto-add all appropriate css headers through the appropriate
 * drupal css calls.
 *
 * The following meta are ignored because drupal core already handles them:
 *   - Content-Type
 *   - Generator
 *
 * Why:
 *   Theme *.tpl.php files should not ever have to call generate or perform
 *   isset()/empty() checks to prevent errors from happening.
 *   All of this work should be done in the template.php.
 *   There is not a standard way of doing this such that other modules and
 *   themes can hook into.
 *   This also allows custom modules to alter themes without having to hack or
 *   alter any existing theme that supports these functions.
 *
 * @param array $cf
 *   An array of header elements to process.
 * @param array $function_history
 *   (optional) An array of function names, ie:
 *   array('0' => 'my_function_name').
 *
 * @return string
 *   A string of html data.
 */
function cf_theme_generate_headers(array $cf, array $function_history = array()) {
  $output = '';

  // handle meta tags
  if (!empty($cf['meta']['charset'])) {
    $output .= '<meta charset="' . filter_xss($cf['meta']['charset'], array()) . '">' . "\n";
  }
  $supported_meta = array();
  $supported_meta[] = 'abstract';
  $supported_meta[] = 'author';
  $supported_meta[] = 'classification';
  $supported_meta[] = 'copyright';
  $supported_meta[] = 'description';
  $supported_meta[] = 'distribution';
  $supported_meta[] = 'doc-class';
  $supported_meta[] = 'doc-rights';
  $supported_meta[] = 'doc-type';
  $supported_meta[] = 'DownloadOptions';
  $supported_meta[] = 'expires';
  $supported_meta[] = 'generator';
  $supported_meta[] = 'googlebot';
  $supported_meta[] = 'keywords';
  $supported_meta[] = 'MSSmartTagsPreventParsing';
  $supported_meta[] = 'name';
  $supported_meta[] = 'owner';
  $supported_meta[] = 'progid';
  $supported_meta[] = 'rating';
  $supported_meta[] = 'refresh';
  $supported_meta[] = 'reply-to';
  $supported_meta[] = 'resource-type';
  $supported_meta[] = 'revisit-after';
  $supported_meta[] = 'robots';
  $supported_meta[] = 'Template';
  foreach ($supported_meta as $tag) {
    if (!empty($cf['meta']['name'][$tag])) {
      $output .= '<meta name="' . $tag . '" content="' . filter_xss($cf['meta']['name'][$tag], array()) . '">' . "\n";
    }
  }
  $supported_http_equiv = array();
  $supported_http_equiv[] = 'cache-control';
  $supported_http_equiv[] = 'content-language';
  $supported_http_equiv[] = 'content-type';
  $supported_http_equiv[] = 'date';
  $supported_http_equiv[] = 'expires';
  $supported_http_equiv[] = 'last-modified';
  $supported_http_equiv[] = 'location';
  $supported_http_equiv[] = 'refresh';
  $supported_http_equiv[] = 'set-cookie';
  $supported_http_equiv[] = 'window-target';
  $supported_http_equiv[] = 'X-UA-Compatible';

  // for specifying minimum Internet Explorer version
  foreach ($supported_http_equiv as $tag) {
    if (!empty($cf['meta']['http-equiv'][$tag])) {
      $output .= '<meta http-equiv="' . $tag . '" content="' . filter_xss($cf['meta']['http-equiv'][$tag], array()) . '">' . "\n";
    }
  }

  // handle css (Currently not working)

  /*
  foreach ($cf['css'] as $key => &$css) {
    if (!empty($css['data'])) {
      drupal_add_css($css['data'], (!empty($css['options']) ? $css['options'] : NULL));
    }
  }
  */
  return $output;
}

/**
 * Safely render all variables specified in the $keys array.
 *
 * Why:
 *   Theme *.tpl.php files should not ever have to call generate or perform
 *   isset()/empty() checks to prevent errors from happening.
 *   All of this work should be done in the template.php.
 *   There is not a standard way of doing this such that other modules and
 *   themes can hook into.
 *   This also allows custom modules to alter themes without having to hack or
 *   alter any existing theme that supports these functions.
 *
 * @param array $variables
 *   The variables array to process.
 * @param array $keys
 *   An array of key names to process.
 * @param array $function_history
 *   (optional) An array of function names, ie:
 *   array('0' => 'my_function_name').
 * @param string $subdir
 *   (optional) A string representing a subdirectory inside of the variables
 *   parameter.
 */
function cf_theme_render_variables(&$variables, $keys, $subdir = NULL, array $function_history = array()) {
  if (is_null($subdir)) {
    foreach ($keys as $key) {
      if (empty($variables[$key])) {
        $variables[$key] = '';
        $variables['cf']['show'][$key] = FALSE;
      }
      else {
        $variables[$key] = render($variables[$key]);
        $variables['cf']['show'][$key] = TRUE;
      }
    }
  }
  else {
    $variables['cf']['show'][$subdir] = array();
    foreach ($keys as $key) {
      if (empty($variables[$subdir][$key])) {
        $variables[$subdir][$key] = '';
        $variables['cf']['show'][$subdir][$key] = FALSE;
      }
      else {
        $variables[$subdir][$key] = render($variables[$subdir][$key]);
        $variables['cf']['show'][$subdir][$key] = TRUE;
      }
    }
  }
}

/**
 * Returns a string with all non-word characters turned into underscores.
 *
 * Why:
 *   Drupals core css cleanup code does not properly handle all allowed css,
 *   namely underscores.
 *   This is a quick-way to ensure that all non-word characters are removed
 *   from a string to be used in css.
 *   This function is intended to be used to only create part of a string as
 *   done throughout the cf_theme_* functions to generate css names, such as:
 *   at-www_drupal_org.
 *
 * @param string $string
 *   The string to cleanup.
 * @param array $function_history
 *   (optional) An array of function names, ie:
 *   array('0' => 'my_function_name').
 *
 * @return string|false
 *   A string with all non-word characters turned into underscores.
 *   FALSE is returned if the preg_replace() functions returns something other
 *   than a string.
 */
function cf_theme_safe_css_string_part($string, array $function_history = array()) {
  $replacement = preg_replace('/(\\W)+/i', '_', $string);
  if (is_string($replacement)) {
    return $replacement;
  }
  return FALSE;
}

Functions

Namesort descending Description
cf_theme_generate_headers Properly generates html headers based on the contents of the $cf parameter.
cf_theme_get_variables Returns an array of variables to be used by a given theme.
cf_theme_render_variables Safely render all variables specified in the $keys array.
cf_theme_safe_css_string_part Returns a string with all non-word characters turned into underscores.