summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
authorGábor Hojtsy <gabor@hojtsy.hu>2007-12-07 11:14:05 +0000
committerGábor Hojtsy <gabor@hojtsy.hu>2007-12-07 11:14:05 +0000
commit5d8cf1b865b1a926957bbc8802618dad08506fe0 (patch)
tree0b98501305afb71736f8119a24676032b901f40a /includes
parent914ccb6f03e6d7e7de62b9084dd7770f89092ee5 (diff)
downloadbrdo-5d8cf1b865b1a926957bbc8802618dad08506fe0.tar.gz
brdo-5d8cf1b865b1a926957bbc8802618dad08506fe0.tar.bz2
#113607 by Steven, chx, hass, catch and dvessel: proper inclusion of style sheets when/where @import is used
Diffstat (limited to 'includes')
-rw-r--r--includes/common.inc115
1 files changed, 98 insertions, 17 deletions
diff --git a/includes/common.inc b/includes/common.inc
index a6128675d..1da58971e 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1732,16 +1732,12 @@ function drupal_build_css_cache($types, $filename) {
foreach ($types as $type) {
foreach ($type as $file => $cache) {
if ($cache) {
- $contents = file_get_contents($file);
- // Remove multiple charset declarations for standards compliance (and fixing Safari problems)
- $contents = preg_replace('/^@charset\s+[\'"](\S*)\b[\'"];/i', '', $contents);
- // 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, '/')) .'/';
- // Wraps all @import arguments in url().
- $contents = preg_replace('/@import\s+(?!url)[\'"]?(\S*)\b[\'"]?/i', '@import url("\1")', $contents);
- // Fix all paths within this CSS file, ignoring absolute paths.
- $data .= preg_replace('/url\(([\'"]?)(?![a-z]+:)/i', 'url(\1'. $path .'\2', $contents);
+ $contents = drupal_load_stylesheet($file, TRUE);
+ // Return the path to where this CSS file originated from.
+ $base = base_path() . dirname($file) .'/';
+ _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);
}
}
}
@@ -1753,13 +1749,6 @@ function drupal_build_css_cache($types, $filename) {
$data = preg_replace($regexp, '', $data);
$data = implode('', $matches[0]) . $data;
- // Perform some safe CSS optimizations.
- $data = preg_replace('<
- \s*([@{}:;,]|\)\s|\s\()\s* | # Remove whitespace around separators, but keep space around parentheses.
- /\*([^*\\\\]|\*(?!/))+\*/ | # Remove comments that are not CSS hacks.
- [\n\r] # Remove line breaks.
- >x', '\1', $data);
-
// Create the CSS file.
file_save_data($data, $csspath .'/'. $filename, FILE_EXISTS_REPLACE);
}
@@ -1767,6 +1756,98 @@ function drupal_build_css_cache($types, $filename) {
}
/**
+ * Helper function for drupal_build_css_cache().
+ *
+ * This function will prefix all paths within a CSS file.
+ */
+function _drupal_build_css_path($matches, $base = NULL) {
+ static $_base;
+ // Store base path for preg_replace_callback.
+ if (isset($base)) {
+ $_base = $base;
+ }
+
+ // Prefix with base and remove '../' segments where possible.
+ $path = $_base . $matches[1];
+ $last = '';
+ while ($path != $last) {
+ $last = $path;
+ $path = preg_replace('`(^|/)(?!../)([^/]+)/../`', '$1', $path);
+ }
+ return 'url('. $path .')';
+}
+
+/**
+ * Loads the stylesheet and resolves all @import commands.
+ *
+ * Loads a stylesheet and replaces @import commands with the contents of the
+ * imported file. Use this instead of file_get_contents when processing
+ * stylesheets.
+ *
+ * The returned contents are compressed removing white space and comments only
+ * when CSS aggregation is enabled. This optimization will not apply for
+ * color.module enabled themes with CSS aggregation turned off.
+ *
+ * @param $file
+ * Name of the stylesheet to be processed.
+ * @param $optimize
+ * Defines if CSS contents should be compressed or not.
+ * @return
+ * Contents of the stylesheet including the imported stylesheets.
+ */
+function drupal_load_stylesheet($file, $optimize = NULL) {
+ static $_optimize;
+ // Store optimization parameter for preg_replace_callback with nested @import loops.
+ if (isset($optimize)) {
+ $_optimize = $optimize;
+ }
+
+ $contents = '';
+ if (file_exists($file)) {
+ // Load the local CSS stylesheet.
+ $contents = file_get_contents($file);
+
+ // Change to the current stylesheet's directory.
+ $cwd = getcwd();
+ chdir(dirname($file));
+
+ // Replaces @import commands with the actual stylesheet content.
+ // This happens recursively but omits external files.
+ $contents = preg_replace_callback('/@import\s*(?:url\()?[\'"]?(?![a-z]+:)([^\'"\()]+)[\'"]?\)?;/', '_drupal_load_stylesheet', $contents);
+ // Remove multiple charset declarations for standards compliance (and fixing Safari problems).
+ $contents = preg_replace('/^@charset\s+[\'"](\S*)\b[\'"];/i', '', $contents);
+
+ if ($_optimize) {
+ // Perform some safe CSS optimizations.
+ $contents = preg_replace('<
+ \s*([@{}:;,]|\)\s|\s\()\s* | # Remove whitespace around separators, but keep space around parentheses.
+ /\*([^*\\\\]|\*(?!/))+\*/ | # Remove comments that are not CSS hacks.
+ [\n\r] # Remove line breaks.
+ >x', '\1', $contents);
+ }
+
+ // Change back directory.
+ chdir($cwd);
+ }
+
+ return $contents;
+}
+
+/**
+ * Loads stylesheets recursively and returns contents with corrected paths.
+ *
+ * This function is used for recursive loading of stylesheets and
+ * returns the stylesheet content with all url() paths corrected.
+ */
+function _drupal_load_stylesheet($matches) {
+ $filename = $matches[1];
+ // Load the imported stylesheet and replace @import commands in there as well.
+ $file = drupal_load_stylesheet($filename);
+ // Alter all url() paths, but not external.
+ return preg_replace('/url\(([\'"]?)(?![a-z]+:)([^\'")]+)[\'"]?\)?;/i', 'url(\1'. dirname($filename) .'/', $file);
+}
+
+/**
* Delete all cached CSS files.
*/
function drupal_clear_css_cache() {