summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2009-07-30 19:57:10 +0000
committerDries Buytaert <dries@buytaert.net>2009-07-30 19:57:10 +0000
commit1a5c71e2dab7a4ea03fce8edd850022abd641d20 (patch)
tree769112ea6b3cdae62668354a115be6317a6fb420 /includes
parenteb34d29999f0f0c4f36201cb01be9f936f9a1fc1 (diff)
downloadbrdo-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.inc205
-rw-r--r--includes/theme.inc2
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));
}
}