public function mimemail_compress::compress in Mime Mail 6
Same name and namespace in other branches
- 7 modules/mimemail_compress/mimemail_compress.inc \mimemail_compress::compress()
File
- modules/
mimemail_compress/ mimemail_compress.inc, line 52 - Converts CSS styles into inline style attributes.
Class
- mimemail_compress
- Compress HTML and CSS into combined message.
Code
public function compress() {
if (!class_exists('DOMDocument', FALSE)) {
return $this->html;
}
$body = $this->html;
// Process the CSS here, turning the CSS style blocks into inline CSS.
if (count($this->unprocessable_tags)) {
$unprocessable_tags = implode('|', $this->unprocessable_tags);
$body = preg_replace("/<({$unprocessable_tags})[^>]*>/i", '', $body);
}
$err = error_reporting(0);
$doc = new DOMDocument();
// Try to set character encoding.
if (function_exists('mb_convert_encoding')) {
$body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
$doc->encoding = "UTF-8";
}
$doc->strictErrorChecking = FALSE;
$doc->formatOutput = TRUE;
$doc
->loadHTML($body);
$doc
->normalizeDocument();
$xpath = new DOMXPath($doc);
// Get rid of comments.
$css = preg_replace('/\\/\\*.*\\*\\//sU', '', $this->css);
// Process the CSS file for selectors and definitions.
preg_match_all('/^\\s*([^{]+){([^}]+)}/mis', $css, $matches);
$all_selectors = array();
foreach ($matches[1] as $key => $selector_string) {
// If there is a blank definition, skip.
if (!strlen(trim($matches[2][$key]))) {
continue;
}
// Else split by commas and duplicate attributes so we can sort by selector precedence.
$selectors = explode(',', $selector_string);
foreach ($selectors as $selector) {
// Don't process pseudo-classes.
if (strpos($selector, ':') !== FALSE) {
continue;
}
$all_selectors[] = array(
'selector' => $selector,
'attributes' => $matches[2][$key],
'index' => $key,
);
}
}
// Now sort the selectors by precedence.
usort($all_selectors, array(
'self',
'sort_selector_precedence',
));
// Before we begin processing the CSS file, parse the document for inline
// styles and append the normalized properties (i.e., 'display: none'
// instead of 'DISPLAY: none') as selectors with full paths (highest
// precedence), so they override any file-based selectors.
$nodes = @$xpath
->query('//*[@style]');
if ($nodes->length > 0) {
foreach ($nodes as $node) {
$style = preg_replace('/[A-z\\-]+(?=\\:)/Se', "drupal_strtolower('\\0')", $node
->getAttribute('style'));
$all_selectors[] = array(
'selector' => $this
->calculateXPath($node),
'attributes' => $style,
);
}
}
foreach ($all_selectors as $value) {
// Query the body for the xpath selector.
$nodes = $xpath
->query($this
->css_to_xpath(trim($value['selector'])));
foreach ($nodes as $node) {
// If it has a style attribute, get it, process it, and append (overwrite) new stuff.
if ($node
->hasAttribute('style')) {
// Break it up into an associative array.
$old_style = $this
->css_style_to_array($node
->getAttribute('style'));
$new_style = $this
->css_style_to_array($value['attributes']);
// New styles overwrite the old styles (not technically accurate, but close enough).
$compressed = array_merge($old_style, $new_style);
$style = '';
foreach ($compressed as $k => $v) {
$style .= drupal_strtolower($k) . ':' . $v . ';';
}
}
else {
// Otherwise create a new style.
$style = trim($value['attributes']);
}
$node
->setAttribute('style', $style);
// Convert float to align for images.
$float = preg_match('/float:(left|right)/', $style, $matches);
if ($float) {
$node
->setAttribute('align', $matches[1]);
$node
->setAttribute('vspace', 5);
$node
->setAttribute('hspace', 5);
}
}
}
// This removes styles from your email that contain display:none. You could comment these out if you want.
$nodes = $xpath
->query('//*[contains(translate(@style," ",""), "display:none")]');
foreach ($nodes as $node) {
$node->parentNode
->removeChild($node);
}
if (variable_get('mimemail_preserve_class', 0) == FALSE) {
$nodes = $xpath
->query('//*[@class]');
foreach ($nodes as $node) {
$node
->removeAttribute('class');
}
}
error_reporting($err);
return $doc
->saveHTML();
}