You are here

css.inc in Advanced CSS/JS Aggregation 7

File

includes/css.inc
View source
<?php

function advagg_process_html_css(&$variables) {

  // dpm($variables);
  return;
  $schema = advagg_get_server_schema();
  $css_var = $variables['css'];
  $css_orig = $css_var;
  if (!variable_get('advagg_only_css_from_variables', ADVAGG_ONLY_CSS_FROM_VARIABLES)) {
    $css_func = drupal_add_css(CSS_DEFAULT);
    advagg_css_array_fixer($css_func);
  }
  else {
    $css_func = array();
  }
  $css = array_merge($css_var, $css_func);
  $css_func_inline = advagg_add_css_inline();
  if (!empty($css_func_inline)) {
    $css = advagg_merge_inline_css($css, $css_func_inline);
  }
  $css_conditional_styles = !empty($variables['conditional_styles']) ? $variables['conditional_styles'] : '';
  $css_styles = $variables['styles'];

  // Try cache.
  if (variable_get('advagg_use_full_cache', ADVAGG_USE_FULL_CACHE)) {

    // Build the cache ID
    // md5 of the CSS input
    // http or https
    // hostname
    // the js rendering function
    // css/js query string
    $cid = 'advagg_processor:css:' . md5(serialize(array(
      $css,
      $css_conditional_styles,
    ))) . ':' . $schema . ':' . $_SERVER['HTTP_HOST'] . ':' . variable_get('advagg_css_render_function', ADVAGG_CSS_RENDER_FUNCTION) . ':' . substr(variable_get('css_js_query_string', '0'), 0, 1);
    $cache = cache_get($cid, 'cache_advagg_bundle_reuse');
  }
  elseif (isset($cid)) {
    unset($cid);
  }
  if (!empty($cache->data)) {
    $variables['styles'] = $cache->data;
  }
  else {

    // Build HTML code.
    $processed_css = advagg_process_css($css);
    if (!empty($processed_css)) {
      $variables['styles'] = $processed_css;
    }
    $variables['styles'] .= $css_conditional_styles;

    // Cache output.
    if (isset($cid) && variable_get('advagg_use_full_cache', ADVAGG_USE_FULL_CACHE) && lock_acquire($cid)) {
      cache_set($cid, $variables['styles'], 'cache_advagg_bundle_reuse', CACHE_TEMPORARY);
      lock_release($cid);
    }
  }
}

/**
 * Returns a themed representation of all stylesheets that should be attached to
 * the page.
 *
 * @see drupal_get_css()
 *
 * It loads the CSS in order, with 'module' first, then 'theme' afterwards.
 * This ensures proper cascading of styles so themes can easily override
 * module styles through CSS selectors.
 *
 * Themes may replace module-defined CSS files by adding a stylesheet with the
 * same filename. For example, themes/garland/system-menus.css would replace
 * modules/system/system-menus.css. This allows themes to override complete
 * CSS files, rather than specific selectors, when necessary.
 *
 * If the original CSS file is being overridden by a theme, the theme is
 * responsible for supplying an accompanying RTL CSS file to replace the
 * module's.
 *
 * @param $css
 *   (optional) An array of CSS files. If no array is provided, the default
 *   stylesheets array is used instead.
 * @param $noagg
 *   (optional) Bool indicating that aggregation should be disabled if TRUE.
 * @return
 *   A string of XHTML CSS tags.
 */
function advagg_process_css($css = NULL, $noagg = FALSE) {
  global $conf;
  $original_css = $css;
  if (!isset($css)) {
    $css = drupal_add_css(CSS_DEFAULT);
  }
  if (empty($css)) {
    return FALSE;
  }

  // Get useful info.
  list($preprocess_css, $scheme, $query_string) = advagg_process_css_js_prep($noagg, 'css');

  // Invoke hook_advagg_css_pre_alter() to give installed modules a chance to
  // modify the data in the $javascript array if necessary.
  drupal_alter('advagg_css_pre', $css, $preprocess_css, $scheme);

  // Set variables.
  $external_no_preprocess = array();
  $module_no_preprocess = array();
  $output_no_preprocess = array();
  $output_preprocess = array();
  $theme_no_preprocess = array();
  $inline_no_preprocess = array();
  $files_included = array();
  $files_aggregates_included = array();
  $inline_included = array();

  // Process input.
  foreach ($css as $media => $types) {

    // Setup some variables
    $files_included[$media] = array();
    $files_aggregates_included[$media] = array();
    $inline_included[$media] = array();

    // If CSS preprocessing is off, we still need to output the styles.
    // Additionally, go through any remaining styles if CSS preprocessing is on
    // and output the non-cached ones.
    foreach ($types as $type => $files) {
      if ($type == 'module') {

        // Setup theme overrides for module styles.
        $theme_styles = array();
        foreach (array_keys($css[$media]['theme']) as $theme_style) {
          $theme_styles[] = basename($theme_style);
        }
      }
      foreach ($types[$type] as $file => $preprocess) {

        // If the theme supplies its own style using the name of the module
        // style, skip its inclusion. This includes any RTL styles associated
        // with its main LTR counterpart.
        if ($type == 'module' && in_array(str_replace('-rtl.css', '.css', basename($file)), $theme_styles)) {

          // Unset the file to prevent its inclusion when CSS aggregation is enabled.
          unset($types[$type][$file]);
          continue;
        }

        // If a CSS file is not to be preprocessed and it's an inline CSS blob
        // it needs to *always* appear at the *very bottom*.
        if ($type == 'inline') {
          if (is_array($preprocess)) {
            foreach ($preprocess as $suffix => $blob) {
              $blob = advagg_drupal_load_stylesheet_content($blob, $preprocess);

              // Invoke hook_advagg_css_inline_alter() to give installed modules
              // a chance to modify the contents of $blob if necessary.
              drupal_alter('advagg_css_inline', $blob);
              $inline_no_preprocess[] = array(
                'media' => $media,
                'data' => $blob,
                'prefix' => $file,
                'suffix' => $suffix,
              );
              $inline_included[$media][] = $blob;
            }
          }

          // Unset to prevent its inclusion.
          unset($types[$type][$file]);
          continue;
        }
        $prefix = '';
        $suffix = '';

        // Invoke hook_advagg_css_extra_alter() to
        // give installed modules a chance to modify the prefix or suffix for a
        // given filename.
        $values = array(
          $file,
          NULL,
          $prefix,
          $suffix,
        );
        drupal_alter('advagg_css_extra', $values);
        list($file, $null, $prefix, $suffix) = $values;
        if ($type == 'inline') {
          $file = advagg_drupal_load_stylesheet_content($file, $preprocess);

          // Invoke hook_advagg_css_inline_alter() to give installed modules a
          // chance to modify the contents of $file if necessary.
          drupal_alter('advagg_css_inline', $file);
          $inline_no_preprocess[] = array(
            'media' => $media,
            'data' => $file,
            'prefix' => $prefix,
            'suffix' => $suffix,
          );
          $inline_included[$media][] = $file;

          // Unset to prevent its inclusion.
          unset($types[$type][$file]);
          continue;
        }

        // If a CSS file is not to be preprocessed and it's an external
        // CSS file, it needs to *always* appear at the *very top*,
        // regardless of whether preprocessing is on or off.
        if ($type == 'external') {
          $external_no_preprocess[] = array(
            'media' => $media,
            'href' => $file,
            'prefix' => $prefix,
            'suffix' => $suffix,
          );
          $files_included[$media][$file] = TRUE;

          // Unset the file to prevent its inclusion.
          unset($types[$type][$file]);
          continue;
        }

        // Only include the stylesheet if it exists.
        if (advagg_file_exists($file)) {
          if (!$preprocess || !($scheme === 'public' && $preprocess_css)) {

            // Create URI for file.
            $file_uri = advagg_build_uri($file) . $query_string;
            $files_included[$media][$file] = $preprocess;

            // If a CSS file is not to be preprocessed and it's a module CSS
            // file, it needs to *always* appear at the *top*, regardless of
            // whether preprocessing is on or off.
            if (!$preprocess && $type == 'module') {
              $module_no_preprocess[] = array(
                'media' => $media,
                'href' => $file_uri,
                'prefix' => $prefix,
                'suffix' => $suffix,
              );
            }
            elseif (!$preprocess && $type == 'theme') {
              $theme_no_preprocess[] = array(
                'media' => $media,
                'href' => $file_uri,
                'prefix' => $prefix,
                'suffix' => $suffix,
              );
            }
            else {
              $output_no_preprocess[] = array(
                'media' => $media,
                'href' => $file_uri,
                'prefix' => $prefix,
                'suffix' => $suffix,
              );
            }
          }
        }
      }
    }
    if ($scheme == 'public' && $preprocess_css) {
      $files_aggregates_included[$media] = $files_included[$media];
      $files = array();
      foreach ($types as $type) {
        foreach ($type as $file => $cache) {
          if ($cache) {
            $files[] = $file;
            $files_included[$media][$file] = TRUE;
            unset($files_aggregates_included[$file]);
          }
        }
      }
      if (!empty($files)) {
        $preprocess_files = advagg_css_js_file_builder('css', $files, $query_string);
        if (!empty($preprocess_files)) {
          $good = TRUE;
          foreach ($preprocess_files as $preprocess_file => $extra) {

            // Empty aggregate, skip
            if (empty($preprocess_file)) {
              continue;
            }
            if ($extra !== FALSE && is_array($extra)) {
              $prefix = $extra['prefix'];
              $suffix = $extra['suffix'];
              $output_preprocess[] = array(
                'media' => $media,
                'href' => advagg_build_uri($preprocess_file),
                'prefix' => $prefix,
                'suffix' => $suffix,
              );
              $files_aggregates_included[$media][$preprocess_file] = $extra;
            }
            else {
              $good = FALSE;
              break;
            }
          }
        }
        if (empty($good)) {

          // Redo with aggregation turned off and return the new value.
          watchdog('advagg', 'CSS aggregation failed. %filename could not be saved correctly.', array(
            '%filename' => $preprocess_file,
          ), WATCHDOG_ERROR);
          $data = advagg_process_css($original_css, TRUE);
          return $data;
        }
      }
    }
  }

  // Default function called: advagg_unlimited_css_builder
  $function = variable_get('advagg_css_render_function', ADVAGG_CSS_RENDER_FUNCTION);
  return $function($external_no_preprocess, $module_no_preprocess, $output_no_preprocess, $output_preprocess, $theme_no_preprocess, $inline_no_preprocess, $inline_included, $files_included, $files_aggregates_included);
}

/**
 * Logic to figure out what kind of css tags to use.
 *
 * @param $external_no_preprocess
 *   array of css files ($media, $href, $prefix, $suffix)
 * @param $module_no_preprocess
 *   array of css files ($media, $href, $prefix, $suffix)
 * @param $output_no_preprocess
 *   array of css files ($media, $href, $prefix, $suffix)
 * @param $output_preprocess
 *   array of css files ($media, $href, $prefix, $suffix)
 * @param $theme_no_preprocess
 *   array of css files ($media, $href, $prefix, $suffix)
 * @param $inline_no_preprocess
 *   array of css data to inline ($media, $data)
 * @param $inline_included
 *   array of inline css included. $a[$media][] = $datablob;
 * @param $files_included
 *   array of css files included. $a[$media][] = $filename
 * @param $files_aggregates_included
 *   array of css files & aggregates included. $a[$media][] = $filename
 * @return
 *   html for loading the css. html for the head.
 */
function advagg_unlimited_css_builder($external_no_preprocess, $module_no_preprocess, $output_no_preprocess, $output_preprocess, $theme_no_preprocess, $inline_no_preprocess, $files_included, $files_aggregates_included, $inline_included) {
  global $user;
  $styles = '';
  $files = array_merge($external_no_preprocess, $module_no_preprocess, $output_no_preprocess, $output_preprocess, $theme_no_preprocess, $inline_no_preprocess);

  // Select method for css html output
  if (count($files) < variable_get('advagg_css_count_threshold', ADVAGG_CSS_COUNT_THRESHOLD)) {
    advagg_unlimited_css_traditional($files, $styles);
  }
  elseif (variable_get('advagg_css_logged_in_ie_detect', ADVAGG_CSS_LOGGED_IN_IE_DETECT) && $user->uid != 0) {

    // Detect IE browsers here
    $is_ie = FALSE;
    if (isset($_SERVER['HTTP_USER_AGENT'])) {

      // Strings for testing found via
      // http://chrisschuld.com/projects/browser-php-detecting-a-users-browser-from-php/
      // Test for v1 - v1.5 IE
      // Test for versions > 1.5
      // Test for Pocket IE
      if (stristr($_SERVER['HTTP_USER_AGENT'], 'microsoft internet explorer') || stristr($_SERVER['HTTP_USER_AGENT'], 'msie') || stristr($_SERVER['HTTP_USER_AGENT'], 'mspie')) {
        $is_ie = TRUE;
      }
    }
    else {
      $is_ie = TRUE;
    }
    if ($is_ie) {
      advagg_unlimited_css_import(array_merge($external_no_preprocess, $module_no_preprocess, $output_no_preprocess), $styles);
      advagg_unlimited_css_import($output_preprocess, $styles);
      advagg_unlimited_css_import($theme_no_preprocess, $styles);
      advagg_unlimited_css_traditional($inline_no_preprocess, $styles);
    }
    else {
      advagg_unlimited_css_traditional($files, $styles);
    }
  }
  else {
    advagg_unlimited_css_import(array_merge($external_no_preprocess, $module_no_preprocess, $output_no_preprocess), $styles);
    advagg_unlimited_css_import($output_preprocess, $styles);
    advagg_unlimited_css_import($theme_no_preprocess, $styles);
    advagg_unlimited_css_traditional($inline_no_preprocess, $styles);
  }
  return $styles;
}

/**
 * Use link tags for CSS
 *
 * @param $files
 *   array of css files ($media, $href, $prefix, $suffix)
 * @param &$styles
 *   html string
 */
function advagg_unlimited_css_traditional($files, &$styles) {
  $last_prefix = '';
  $last_suffix = '';
  foreach ($files as $css_file) {
    $media = $css_file['media'];
    $prefix = empty($css_file['prefix']) ? '' : $css_file['prefix'] . "\n";
    $suffix = empty($css_file['suffix']) ? '' : $css_file['suffix'];

    // Group prefixes and suffixes.
    if (isset($css_file['href'])) {
      $href = $css_file['href'];
      if ($prefix != $last_prefix) {
        $styles .= $last_suffix . "\n" . $prefix . '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . $href . '" />' . "\n";
      }
      else {
        $styles .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . $href . '" />' . "\n";
      }
    }
    else {
      $data = $css_file['data'];
      if ($prefix != $last_prefix) {
        $styles .= $last_suffix . "\n" . $prefix . '<style type="text/css" media="' . $media . '">' . "\n" . $data . "\n" . '</style>' . "\n";
      }
      else {
        $styles .= '<style type="text/css" media="' . $media . '">' . "\n" . $data . "\n" . '</style>' . "\n";
      }
    }
    $last_prefix = $prefix;
    $last_suffix = $suffix;
  }
  $styles .= empty($last_suffix) ? '' : $last_suffix . "\n";
}

/**
 * Use import tags for CSS
 *
 * @param $files
 *   array of css files ($media, $href)
 * @param &$styles
 *   html string
 */
function advagg_unlimited_css_import($files, &$styles) {
  $counter = 0;
  $media = NULL;
  $import = '';
  foreach ($files as $css_file) {
    $media_new = $css_file['media'];
    $href = $css_file['href'];
    if ($media_new != $media || $counter > variable_get('advagg_css_count_threshold', ADVAGG_CSS_COUNT_THRESHOLD)) {
      if ($media && !empty($import)) {
        $styles .= "\n" . '<style type="text/css" media="' . $media . '">' . "\n" . $import . '</style>';
        $import = '';
      }
      $counter = 0;
      $media = $media_new;
    }
    $import .= '@import "' . $href . '";' . "\n";
    $counter++;
  }
  if ($media && !empty($import)) {
    $styles .= "\n" . '<style type="text/css" media="' . $media . '">' . "\n" . $import . '</style>';
  }
}

Functions

Namesort descending Description
advagg_process_css Returns a themed representation of all stylesheets that should be attached to the page.
advagg_process_html_css
advagg_unlimited_css_builder Logic to figure out what kind of css tags to use.
advagg_unlimited_css_import Use import tags for CSS
advagg_unlimited_css_traditional Use link tags for CSS