Index: update.php =================================================================== RCS file: /cvs/drupal/drupal/update.php,v retrieving revision 1.206 diff -u -F^f -r1.206 update.php --- update.php 28 Nov 2006 20:52:51 -0000 1.206 +++ update.php 2 Dec 2006 01:48:35 -0000 @@ -785,6 +785,9 @@ function update_create_cache_tables() { update_fix_watchdog(); update_fix_sessions(); + // Clear any cached CSS files, in case any module updates its CSS as well. + drupal_clear_css_cache(); + $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; switch ($op) { case 'Update': Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.593 diff -u -F^f -r1.593 common.inc --- includes/common.inc 30 Nov 2006 08:13:31 -0000 1.593 +++ includes/common.inc 2 Dec 2006 01:48:36 -0000 @@ -1362,19 +1362,27 @@ function drupal_add_link($attributes) { * Adds a CSS file to the stylesheet queue. * * @param $path - * The path to the CSS file relative to the base_path(), e.g., /modules/devel/devel.css. + * (optional) The path to the CSS file relative to the base_path(), e.g., /modules/devel/devel.css. * @param $type - * The type of stylesheet that is being added. Types are: core, module, and theme. + * (optional) The type of stylesheet that is being added. Types are: core, module, and theme. * @param $media * (optional) The media type for the stylesheet, e.g., all, print, screen. + * @param $cache + * (optional) Should this CSS file be cached if cache CSS setting is turned on? * @return * An array of CSS files. */ -function drupal_add_css($path = NULL, $type = 'module', $media = 'all') { - static $css = array('core' => array(), 'module' => array(), 'theme' => array()); +function drupal_add_css($path = NULL, $type = 'module', $media = 'all', $cache = TRUE) { + static $css = array(); - if (!is_null($path)) { - $css[$type][$path] = array('path' => $path, 'media' => $media); + // Create an array of CSS files for each media type first, since each type needs to be served + // to the browser differently. + if (isset($path)) { + // This check is necessary to ensure proper cascading of styles and is faster than an asort(). + if (!isset($css[$media])) { + $css[$media] = array('core' => array(), 'module' => array(), 'theme' => array()); + } + $css[$media][$type][$path] = $cache; } return $css; @@ -1392,13 +1400,34 @@ function drupal_add_css($path = NULL, $t */ function drupal_get_css($css = NULL) { $output = ''; - if (is_null($css)) { + if (!isset($css)) { $css = drupal_add_css(); } - foreach ($css as $type) { - foreach ($type as $file) { - $output .= '\n"; + $cache_css = variable_get('cache_css', FALSE); + $directory_path = file_directory_path(); + $is_writable = is_writable($directory_path); + + foreach ($css as $media => $types) { + if ($is_writable && $cache_css) { + $filename = md5(serialize($types)) .'.css'; + $path = $directory_path .'/css/'; + + if (!file_exists($path . $filename)) { + drupal_build_css_cache($types, $filename); + } + + $output .= ''. "\n"; + } + + // If CSS caching is off, we still need to ouput the styles. + // Additionally, go through any remaining styles if CSS caching is on and output the non-cached ones. + foreach ($types as $type) { + foreach ($type as $file => $cache) { + if (!$cache || !$cache_css) { + $output .= '' ."\n"; + } + } } } @@ -1406,6 +1435,67 @@ function drupal_get_css($css = NULL) { } /** + * 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 $filename + * The name of the aggregate CSS file. + * @return + * The name of the CSS file. + */ +function drupal_build_css_cache($types, $filename) { + $data = ''; + + // Create the css/ within the files folder. + file_check_directory(file_create_path('css'), FILE_CREATE_DIRECTORY); + + // Build aggregate CSS file. + foreach ($types as $type) { + foreach ($type as $file => $cache) { + if ($cache) { + $contents = file_get_contents($file); + // Return the path to where this CSS file originated from, stripping off the name of the file at the end of the path. + $path = base_path() . substr($file, 0, strrpos($file, '/')) .'/'; + // Fix all paths within this CSS file, ignoring absolute paths. + $contents = preg_replace('/url\(([\'"]?)(?![a-z]+:)/i', 'url(\1'. $path . '\2', $contents); + // Fix any @import that don't use url() and is not absoslute. + $data .= preg_replace('/@import\s*([\'"]?)(?![a-z]+:)/i', '@import \1'. $path . '\2', $contents); + } + } + } + + // @import rules must proceed any other style, so we move those to the top. + $regexp = '/@import[^;]+;/i'; + preg_match_all($regexp, $data, $matches); + $data = preg_replace($regexp, '', $data); + $data = implode('', $matches[0]) . $data; + + // Perform some safe CSS optimizations. + $data = preg_replace('< + \s*([@{}:;\)])\s* | # Remove whitespace around separators. + /\*([^*\\\\]|\*(?!/))+\*/ | # Remove comments that are not CSS hacks. + [\n\r] # Remove line breaks. + >x', '\1', $data); + + // Allow modules to add in additional compression logic. + foreach (module_implements('compress_css') as $module) { + $function = $module .'_compress_css'; + $function($data); + } + + // Create the CSS file. + file_save_data($data, file_create_path('css') .'/'. $filename, FILE_EXISTS_REPLACE); +} + +/** + * Delete all cached CSS files. + */ +function drupal_clear_css_cache() { + file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE); +} + +/** * Add a JavaScript file, setting or inline code to the page. * * The behavior of this function depends on the parameters it is called with. Index: includes/locale.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/locale.inc,v retrieving revision 1.98 diff -u -F^f -r1.98 locale.inc --- includes/locale.inc 1 Dec 2006 22:47:52 -0000 1.98 +++ includes/locale.inc 2 Dec 2006 01:48:37 -0000 @@ -1284,7 +1284,7 @@ function _locale_export_remove_plural($e */ function _locale_string_language_list($translation) { // Add CSS - drupal_add_css(drupal_get_path('module', 'locale') .'/locale.css'); + drupal_add_css(drupal_get_path('module', 'locale') .'/locale.css', 'module', 'all', FALSE); $languages = locale_supported_languages(FALSE, TRUE); unset($languages['name']['en']); Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.328 diff -u -F^f -r1.328 theme.inc --- includes/theme.inc 29 Nov 2006 20:39:37 -0000 1.328 +++ includes/theme.inc 2 Dec 2006 01:48:38 -0000 @@ -406,7 +406,7 @@ function theme_page($content) { function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) { drupal_set_header('Content-Type: text/html; charset=utf-8'); - drupal_add_css('misc/maintenance.css', 'core'); + drupal_add_css('misc/maintenance.css', 'core', 'all', FALSE); drupal_set_html_head(''); $output = "\n"; Index: modules/block/block.module =================================================================== RCS file: /cvs/drupal/drupal/modules/block/block.module,v retrieving revision 1.241 diff -u -F^f -r1.241 block.module --- modules/block/block.module 1 Dec 2006 22:47:53 -0000 1.241 +++ modules/block/block.module 2 Dec 2006 01:48:39 -0000 @@ -205,7 +205,7 @@ function block_admin_display($theme = NU global $theme_key, $custom_theme; // Add CSS - drupal_add_css(drupal_get_path('module', 'block') .'/block.css'); + drupal_add_css(drupal_get_path('module', 'block') .'/block.css', 'module', 'all', FALSE); // If non-default theme configuration has been selected, set the custom theme. if ($theme) { Index: modules/color/color.module =================================================================== RCS file: /cvs/drupal/drupal/modules/color/color.module,v retrieving revision 1.9 diff -u -F^f -r1.9 color.module --- modules/color/color.module 30 Nov 2006 17:41:03 -0000 1.9 +++ modules/color/color.module 2 Dec 2006 01:48:39 -0000 @@ -41,7 +41,7 @@ function _color_page_alter(&$vars) { // Override stylesheet $path = variable_get('color_'. $theme_key .'_stylesheet', NULL); if ($path) { - $vars['css']['theme'] = array($path => array('path' => $path, 'media' => 'all')); + $vars['css']['all']['theme'][$path] = TRUE; $vars['styles'] = drupal_get_css($vars['css']); } @@ -88,11 +88,11 @@ function color_scheme_form($theme) { $info = color_get_info($theme); // Add Farbtastic color picker - drupal_add_css('misc/farbtastic/farbtastic.css'); + drupal_add_css('misc/farbtastic/farbtastic.css', 'module', 'all', FALSE); drupal_add_js('misc/farbtastic/farbtastic.js'); // Add custom CSS/JS - drupal_add_css($base .'/color.css', 'module'); + drupal_add_css($base .'/color.css', 'module', 'all', FALSE); drupal_add_js($base .'/color.js'); drupal_add_js(array('color' => array( 'reference' => color_get_palette($theme, true) Index: modules/help/help.module =================================================================== RCS file: /cvs/drupal/drupal/modules/help/help.module,v retrieving revision 1.66 diff -u -F^f -r1.66 help.module --- modules/help/help.module 1 Dec 2006 22:47:53 -0000 1.66 +++ modules/help/help.module 2 Dec 2006 01:48:39 -0000 @@ -37,7 +37,7 @@ function help_menu($may_cache) { */ function help_main() { // Add CSS - drupal_add_css(drupal_get_path('module', 'help') .'/help.css'); + drupal_add_css(drupal_get_path('module', 'help') .'/help.css'), 'module', 'all', FALSE); $output = t('