diff options
author | Dries Buytaert <dries@buytaert.net> | 2009-07-30 19:57:10 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2009-07-30 19:57:10 +0000 |
commit | 1a5c71e2dab7a4ea03fce8edd850022abd641d20 (patch) | |
tree | 769112ea6b3cdae62668354a115be6317a6fb420 /includes | |
parent | eb34d29999f0f0c4f36201cb01be9f936f9a1fc1 (diff) | |
download | brdo-1a5c71e2dab7a4ea03fce8edd850022abd641d20.tar.gz brdo-1a5c71e2dab7a4ea03fce8edd850022abd641d20.tar.bz2 |
- Patch #92877 by mfer, Rob Loach, Damien Tournoud, et al: add numeric weight to drupal_add_css.
Diffstat (limited to 'includes')
-rw-r--r-- | includes/common.inc | 205 | ||||
-rw-r--r-- | includes/theme.inc | 2 |
2 files changed, 117 insertions, 90 deletions
diff --git a/includes/common.inc b/includes/common.inc index 18f1467cf..ca996c122 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -40,6 +40,21 @@ define('SAVED_UPDATED', 2); define('SAVED_DELETED', 3); /** + * The default weight of system CSS files added to the page. + */ +define('CSS_SYSTEM', -100); + +/** + * The default weight of CSS files added to the page. + */ +define('CSS_DEFAULT', 0); + +/** + * The default weight of theme CSS files added to the page. + */ +define('CSS_THEME', 100); + +/** * The weight of JavaScript libraries, settings or jQuery plugins being * added to the page. */ @@ -2328,7 +2343,7 @@ function drupal_add_link($attributes) { * @param $data * (optional) The stylesheet data to be added, depending on what is passed * through to the $options['type'] parameter: - * - 'module' or 'theme': The path to the CSS file relative to the base_path(), + * - 'file': The path to the CSS file relative to the base_path(), * e.g., "modules/devel/devel.css". * * Modules should always prefix the names of their CSS files with the @@ -2345,15 +2360,28 @@ function drupal_add_link($attributes) { * directory. This CSS file should contain overrides for properties which * should be reversed or otherwise different in a right-to-left display. * - 'inline': A string of CSS that should be placed in the given scope. Note - * that it is better practice to use 'module' or 'theme' stylesheets, rather - * than 'inline' as the CSS would then be aggregated and cached. + * that it is better practice to use 'file' stylesheets, rather than 'inline' + * as the CSS would then be aggregated and cached. * * @param $options * (optional) A string defining the 'type' of CSS that is being added in the - * $data parameter ('module', 'theme' or 'inline'), or an associative array of - * additional options, with the following keys: - * - 'type': The type of stylesheet that is being added. Types are: 'module', - * 'theme' or 'inline'. Defaults to 'module'. + * $data parameter ('file'/'inline'), or an array which can have any or all of + * the following keys: + * - 'type': The type of stylesheet being added. Available options are 'file' + * or 'inline'. Defaults to 'file'. + * - 'weight': The weight of the stylesheet specifies the order in which the + * CSS will appear when presented on the page. + * + * Available constants are: + * - CSS_SYSTEM: Any system-layer CSS. + * - CSS_DEFAULT: Any module-layer CSS. + * - CSS_THEME: Any theme-layer CSS. + * + * If you need to embed a CSS file before any other module's stylesheets, + * for example, you would use CSS_DEFAULT - 1. Note that inline CSS is + * simply appended to the end of the specified scope (region), so they + * always come last. + * * - 'media': The media type for the stylesheet, e.g., all, print, screen. * Defaults to 'all'. * - 'preprocess': Allows the CSS to be aggregated and compressed if the @@ -2385,7 +2413,6 @@ function drupal_add_link($attributes) { */ function drupal_add_css($data = NULL, $options = NULL) { $css = &drupal_static(__FUNCTION__, array()); - global $language; // Construct the options, taking the defaults into consideration. if (isset($options)) { @@ -2401,25 +2428,26 @@ function drupal_add_css($data = NULL, $options = NULL) { // to the browser differently. if (isset($data)) { $options += array( - 'type' => 'module', + 'type' => 'file', + 'weight' => CSS_DEFAULT, 'media' => 'all', - 'preprocess' => TRUE + 'preprocess' => TRUE, + 'data' => $data, ); - $media = $options['media']; - $type = $options['type']; - // This check is necessary to ensure proper cascading of styles and is faster than an asort(). - if (!isset($css[$media])) { - $css[$media] = array('module' => array(), 'theme' => array(), 'inline' => array()); - } - $css[$media][$type][$data] = $options['preprocess']; + // Always add a tiny value to the weight, to conserve the insertion order. + $options['weight'] += count($css) / 1000; - // If the current language is RTL, add the CSS file with RTL overrides. - if ($type != 'inline' && $language->direction == LANGUAGE_RTL) { - $rtl_path = str_replace('.css', '-rtl.css', $data); - if (file_exists($rtl_path)) { - $css[$media][$type][$rtl_path] = $options['preprocess']; - } + // Add the data to the CSS array depending on the type. + switch ($options['type']) { + case 'file': + $css[$data] = $options; + break; + case 'inline': + // For inline stylesheets, we don't want to use the $data as the array + // key as $data could be a very long string of CSS. + $css[] = $options; + break; } } @@ -2453,9 +2481,6 @@ function drupal_get_css($css = NULL) { if (!isset($css)) { $css = drupal_add_css(); } - $no_module_preprocess = ''; - $no_theme_preprocess = ''; - $no_inline_preprocess = ''; $preprocess_css = (variable_get('preprocess_css', FALSE) && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update')); $directory = file_directory_path(); @@ -2467,76 +2492,82 @@ function drupal_get_css($css = NULL) { // URL changed. $query_string = '?' . substr(variable_get('css_js_query_string', '0'), 0, 1); - foreach ($css as $media => $types) { - // 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 => $information) { - 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); - } + // Allow modules to alter the css items. + drupal_alter('css', $css); + + // Sort css items according to their weights. + uasort($css, 'drupal_sort_weight'); + + // Remove the overriden CSS files. Later CSS files override former ones. + $previous_item = array(); + foreach ($css as $key => $item) { + if ($item['type'] == 'file') { + $basename = basename($item['data']); + if (isset($previous_item[$basename])) { + // Remove the previous item that shared the same base name. + unset($css[$previous_item[$basename]]); } - foreach ($types[$type] as $data => $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($data)), $theme_styles)) { - // Unset the file to prevent its inclusion when CSS aggregation is enabled. - unset($types[$type][$data]); - continue; - } - // Include inline stylesheets. - if ($type == 'inline') { - $no_inline_preprocess .= drupal_load_stylesheet_content($data, $preprocess); + $previous_item[$basename] = $key; + } + } + + // 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. + $rendered_css = array(); + $inline_css = ''; + $preprocess_items = array(); + foreach ($css as $data => $item) { + // Loop through each of the stylesheets, including them appropriately based + // on their type. + switch ($item['type']) { + case 'file': + // Depending on whether aggregation is desired, include the file. + if (!$item['preprocess'] || !($is_writable && $preprocess_css)) { + $rendered_css[] = '<link type="text/css" rel="stylesheet" media="' . $item['media'] . '" href="' . base_path() . $item['data'] . $query_string . '" />'; } - // Only include the stylesheet if it exists. - elseif (file_exists($data)) { - if (!$preprocess || !($is_writable && $preprocess_css)) { - // 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') { - $no_module_preprocess .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $data . $query_string . '" />' . "\n"; - } - // If a CSS file is not to be preprocessed and it's a theme CSS file, it needs to *always* appear at the *bottom*, - // regardless of whether preprocessing is on or off. - elseif (!$preprocess && $type == 'theme') { - $no_theme_preprocess .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $data . $query_string . '" />' . "\n"; - } - else { - $output .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $data . $query_string . '" />' . "\n"; - } - } + else { + $preprocess_items[$item['media']][] = $item; + // Mark the position of the preprocess element, + // it should be at the position of the first preprocessed file. + $rendered_css['preprocess'] = ''; } - } + break; + case 'inline': + // Include inline stylesheets. + $inline_css .= drupal_load_stylesheet_content($item['data'], $item['preprocess']); + break; } + } - if ($is_writable && $preprocess_css) { + if (!empty($preprocess_items)) { + foreach ($preprocess_items as $media => $items) { // Prefix filename to prevent blocking by firewalls which reject files // starting with "ad*". - $filename = 'css_' . md5(serialize($types) . $query_string) . '.css'; - $preprocess_file = drupal_build_css_cache($types, $filename); - $output .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $preprocess_file . '" />' . "\n"; + $filename = 'css_' . md5(serialize($items) . $query_string) . '.css'; + $preprocess_file = drupal_build_css_cache($items, $filename); + $rendered_css['preprocess'] .= '<link type="text/css" rel="stylesheet" media="' . $media . '" href="' . base_path() . $preprocess_file . '" />' . "\n"; } } - if (!empty($no_inline_preprocess)) { - $no_inline_preprocess = '<style type="text/css">' . $no_inline_preprocess . '</style>'; + // Enclose the inline CSS with the style tag if required. + if (!empty($inline_css)) { + $inline_css = "\n" . '<style type="text/css">' . $inline_css .'</style>'; } - return $no_module_preprocess . $output . $no_theme_preprocess . $no_inline_preprocess; + + // Output all the CSS files with the inline stylesheets showing up last. + return implode("\n", $rendered_css) . $inline_css; } /** * Aggregate and optimize CSS files, putting them in the files directory. * - * @param $types - * An array of types of CSS files (e.g., screen, print) to aggregate and - * compress into one file. + * @param $css + * An array of CSS files to aggregate and compress into one file. * @param $filename * The name of the aggregate CSS file. * @return * The name of the CSS file. */ -function drupal_build_css_cache($types, $filename) { +function drupal_build_css_cache($css, $filename) { $data = ''; // Create the css/ within the files folder. @@ -2545,19 +2576,15 @@ function drupal_build_css_cache($types, $filename) { if (!file_exists($csspath . '/' . $filename)) { // Build aggregate CSS file. - foreach ($types as $type => $css) { - // Only 'module' or 'theme' stylesheets can be aggregated. - if ($type == 'module' || $type == 'theme') { - foreach ($css as $stylesheet => $cache) { - if ($cache) { - $contents = drupal_load_stylesheet($stylesheet, TRUE); - // Return the path to where this CSS file originated from. - $base = base_path() . dirname($stylesheet) . '/'; - _drupal_build_css_path(NULL, $base); - // Prefix all paths within this CSS file, ignoring external and absolute paths. - $data .= preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_drupal_build_css_path', $contents); - } - } + foreach ($css as $stylesheet) { + // Only 'file' stylesheets can be aggregated. + if ($stylesheet['type'] == 'file') { + $contents = drupal_load_stylesheet($stylesheet['data'], TRUE); + // Return the path to where this CSS file originated from. + $base = base_path() . dirname($stylesheet['data']) . '/'; + _drupal_build_css_path(NULL, $base); + // Prefix all paths within this CSS file, ignoring external and absolute paths. + $data .= preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', '_drupal_build_css_path', $contents); } } diff --git a/includes/theme.inc b/includes/theme.inc index 661d94e59..d91386166 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -132,7 +132,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb // And now add the stylesheets properly foreach ($final_stylesheets as $media => $stylesheets) { foreach ($stylesheets as $stylesheet) { - drupal_add_css($stylesheet, array('type' => 'theme', 'media' => $media)); + drupal_add_css($stylesheet, array('weight' => CSS_THEME, 'media' => $media)); } } |